1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#define ZEND_INTENSIVE_DEBUGGING 0
23
24#include <stdio.h>
25#include <signal.h>
26
27#include "zend.h"
28#include "zend_compile.h"
29#include "zend_execute.h"
30#include "zend_API.h"
31#include "zend_ptr_stack.h"
32#include "zend_constants.h"
33#include "zend_extensions.h"
34#include "zend_ini.h"
35#include "zend_exceptions.h"
36#include "zend_interfaces.h"
37#include "zend_closures.h"
38#include "zend_generators.h"
39#include "zend_vm.h"
40#include "zend_dtrace.h"
41
42/* Virtual current working directory support */
43#include "zend_virtual_cwd.h"
44
45#define _CONST_CODE  0
46#define _TMP_CODE    1
47#define _VAR_CODE    2
48#define _UNUSED_CODE 3
49#define _CV_CODE     4
50
51typedef int (*incdec_t)(zval *);
52
53#define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
54#define get_zval_ptr_deref(op_type, node, ex, should_free, type) _get_zval_ptr_deref(op_type, node, ex, should_free, type TSRMLS_CC)
55#define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
56#define get_zval_ptr_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
57#define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
58#define get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
59
60/* Prototypes */
61static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
62static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
63static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
64
65#define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
66
67static ZEND_FUNCTION(pass)
68{
69}
70
71static const zend_internal_function zend_pass_function = {
72    ZEND_INTERNAL_FUNCTION, /* type              */
73    0,                      /* fn_flags          */
74    NULL,                   /* name              */
75    NULL,                   /* scope             */
76    NULL,                   /* prototype         */
77    0,                      /* num_args          */
78    0,                      /* required_num_args */
79    NULL,                   /* arg_info          */
80    ZEND_FN(pass),          /* handler           */
81    NULL                    /* module            */
82};
83
84#undef zval_ptr_dtor
85#define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC TSRMLS_CC)
86#define zval_ptr_dtor_nogc(zv) i_zval_ptr_dtor_nogc(zv ZEND_FILE_LINE_CC TSRMLS_CC)
87
88#define PZVAL_LOCK(z) if (Z_REFCOUNTED_P(z)) Z_ADDREF_P((z))
89#define SELECTIVE_PZVAL_LOCK(pzv, opline)   if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }
90
91#define READY_TO_DESTROY(zv) \
92    (zv && Z_REFCOUNTED_P(zv) && Z_REFCOUNT_P(zv) == 1)
93
94#define EXTRACT_ZVAL_PTR(zv) do {                       \
95        zval *__zv = (zv);                              \
96        if (Z_TYPE_P(__zv) == IS_INDIRECT) {            \
97            ZVAL_COPY(__zv, Z_INDIRECT_P(__zv));        \
98        }                                               \
99    } while (0)
100
101#define FREE_OP(should_free) \
102    if (should_free.var) { \
103        if ((zend_uintptr_t)should_free.var & 1L) { \
104            zval_dtor((zval*)((zend_uintptr_t)should_free.var & ~1L)); \
105        } else { \
106            zval_ptr_dtor_nogc(should_free.var); \
107        } \
108    }
109
110#define FREE_OP_IF_VAR(should_free) \
111    if (should_free.var != NULL && (((zend_uintptr_t)should_free.var & 1L) == 0)) { \
112        zval_ptr_dtor_nogc(should_free.var); \
113    }
114
115#define FREE_OP_VAR_PTR(should_free) \
116    if (should_free.var) { \
117        zval_ptr_dtor_nogc(should_free.var); \
118    }
119
120#define TMP_FREE(z) (zval*)(((zend_uintptr_t)(z)) | 1L)
121
122#define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L)
123
124/* End of zend_execute_locks.h */
125
126#define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
127
128#define CTOR_CALL_BIT    0x1
129#define CTOR_USED_BIT    0x2
130
131#define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
132#define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
133
134#define ENCODE_CTOR(ce, used) \
135    ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
136#define DECODE_CTOR(ce) \
137    ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
138
139#undef EX
140#define EX(element) execute_data->element
141
142ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data, uint32_t var)
143{
144    return EX_VAR(var);
145}
146
147static zend_always_inline zval *_get_zval_ptr_tmp(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
148{
149    zval *ret = EX_VAR(var);
150    should_free->var = ret;
151
152    ZEND_ASSERT(Z_TYPE_P(ret) != IS_REFERENCE);
153
154    return ret;
155}
156
157static zend_always_inline zval *_get_zval_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
158{
159    zval *ret = EX_VAR(var);
160
161    should_free->var = ret;
162    return ret;
163}
164
165static zend_always_inline zval *_get_zval_ptr_var_deref(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
166{
167    zval *ret = EX_VAR(var);
168
169    should_free->var = ret;
170    ZVAL_DEREF(ret);
171    return ret;
172}
173
174static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int type, const zend_execute_data *execute_data TSRMLS_DC)
175{
176    zend_string *cv;
177
178    switch (type) {
179        case BP_VAR_R:
180        case BP_VAR_UNSET:
181            cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
182            zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
183            /* break missing intentionally */
184        case BP_VAR_IS:
185            ptr = &EG(uninitialized_zval);
186            break;
187        case BP_VAR_RW:
188            cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
189            zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
190            /* break missing intentionally */
191        case BP_VAR_W:
192            ZVAL_NULL(ptr);
193            break;
194    }
195    return ptr;
196}
197
198static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, uint32_t var, const zend_execute_data *execute_data TSRMLS_DC)
199{
200    zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
201
202    zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
203    return &EG(uninitialized_zval);
204}
205
206static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, uint32_t var, const zend_execute_data *execute_data TSRMLS_DC)
207{
208    zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
209
210    zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
211    return &EG(uninitialized_zval);
212}
213
214static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_IS(zval *ptr, uint32_t var, const zend_execute_data *execute_data TSRMLS_DC)
215{
216    return &EG(uninitialized_zval);
217}
218
219static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, uint32_t var, const zend_execute_data *execute_data TSRMLS_DC)
220{
221    zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
222
223    ZVAL_NULL(ptr);
224    zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
225    return ptr;
226}
227
228static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_W(zval *ptr, uint32_t var, const zend_execute_data *execute_data TSRMLS_DC)
229{
230    ZVAL_NULL(ptr);
231    return ptr;
232}
233
234static zend_always_inline zval *_get_zval_ptr_cv(const zend_execute_data *execute_data, uint32_t var, int type TSRMLS_DC)
235{
236    zval *ret = EX_VAR(var);
237
238    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
239        return _get_zval_cv_lookup(ret, var, type, execute_data TSRMLS_CC);
240    }
241    return ret;
242}
243
244static zend_always_inline zval *_get_zval_ptr_cv_deref(const zend_execute_data *execute_data, uint32_t var, int type TSRMLS_DC)
245{
246    zval *ret = EX_VAR(var);
247
248    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
249        return _get_zval_cv_lookup(ret, var, type, execute_data TSRMLS_CC);
250    }
251    ZVAL_DEREF(ret);
252    return ret;
253}
254
255static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
256{
257    zval *ret = EX_VAR(var);
258
259    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
260        return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data TSRMLS_CC);
261    }
262    return ret;
263}
264
265static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_R(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
266{
267    zval *ret = EX_VAR(var);
268
269    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
270        return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data TSRMLS_CC);
271    }
272    ZVAL_DEREF(ret);
273    return ret;
274}
275
276static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
277{
278    zval *ret = EX_VAR(var);
279
280    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
281        return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data TSRMLS_CC);
282    }
283    return ret;
284}
285
286static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
287{
288    zval *ret = EX_VAR(var);
289
290    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
291        return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data TSRMLS_CC);
292    }
293    ZVAL_DEREF(ret);
294    return ret;
295}
296
297static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
298{
299    zval *ret = EX_VAR(var);
300
301    if (Z_TYPE_P(ret) == IS_UNDEF) {
302        return _get_zval_cv_lookup_BP_VAR_IS(ret, var, execute_data TSRMLS_CC);
303    }
304    return ret;
305}
306
307static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_IS(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
308{
309    zval *ret = EX_VAR(var);
310
311    if (Z_TYPE_P(ret) == IS_UNDEF) {
312        return _get_zval_cv_lookup_BP_VAR_IS(ret, var, execute_data TSRMLS_CC);
313    }
314    ZVAL_DEREF(ret);
315    return ret;
316}
317
318static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
319{
320    zval *ret = EX_VAR(var);
321
322    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
323        return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data TSRMLS_CC);
324    }
325    return ret;
326}
327
328static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
329{
330    zval *ret = EX_VAR(var);
331
332    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
333        return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data TSRMLS_CC);
334    }
335    ZVAL_DEREF(ret);
336    return ret;
337}
338
339static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
340{
341    zval *ret = EX_VAR(var);
342
343    if (Z_TYPE_P(ret) == IS_UNDEF) {
344        return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data TSRMLS_CC);
345    }
346    return ret;
347}
348
349static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
350{
351    return EX_VAR(var);
352}
353
354static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var TSRMLS_DC)
355{
356    zval *ret = EX_VAR(var);
357
358    if (Z_TYPE_P(ret) == IS_UNDEF) {
359        return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data TSRMLS_CC);
360    }
361    ZVAL_DEREF(ret);
362    return ret;
363}
364
365static inline zval *_get_zval_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
366{
367    zval *ret;
368
369    switch (op_type) {
370        case IS_CONST:
371            should_free->var = NULL;
372            return node->zv;
373            break;
374        case IS_TMP_VAR:
375            ret = EX_VAR(node->var);
376            should_free->var = TMP_FREE(ret);
377            return ret;
378            break;
379        case IS_VAR:
380            return _get_zval_ptr_var(node->var, execute_data, should_free TSRMLS_CC);
381            break;
382        case IS_UNUSED:
383            should_free->var = NULL;
384            return NULL;
385            break;
386        case IS_CV:
387        default:
388            should_free->var = NULL;
389            return _get_zval_ptr_cv(execute_data, node->var, type TSRMLS_CC);
390            break;
391    }
392    return NULL;
393}
394
395static inline zval *_get_zval_ptr_deref(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
396{
397    zval *ret;
398
399    switch (op_type) {
400        case IS_CONST:
401            should_free->var = NULL;
402            return node->zv;
403            break;
404        case IS_TMP_VAR:
405            ret = EX_VAR(node->var);
406            should_free->var = TMP_FREE(ret);
407            return ret;
408            break;
409        case IS_VAR:
410            return _get_zval_ptr_var_deref(node->var, execute_data, should_free TSRMLS_CC);
411            break;
412        case IS_UNUSED:
413            should_free->var = NULL;
414            return NULL;
415            break;
416        case IS_CV:
417        default:
418            should_free->var = NULL;
419            return _get_zval_ptr_cv_deref(execute_data, node->var, type TSRMLS_CC);
420            break;
421    }
422    return NULL;
423}
424
425static zend_always_inline zval *_get_zval_ptr_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
426{
427    zval *ret = EX_VAR(var);
428
429    if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
430        should_free->var = NULL;
431        return Z_INDIRECT_P(ret);
432    } else if (!Z_REFCOUNTED_P(ret) || Z_REFCOUNT_P(ret) == 1) {
433        should_free->var = ret;
434        return ret;
435    } else {
436        Z_DELREF_P(ret);
437        should_free->var = NULL;
438        return ret;
439    }
440}
441
442static inline zval *_get_zval_ptr_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
443{
444    if (op_type == IS_CV) {
445        should_free->var = NULL;
446        return _get_zval_ptr_cv(execute_data, node->var, type TSRMLS_CC);
447    } else /* if (op_type == IS_VAR) */ {
448        ZEND_ASSERT(op_type == IS_VAR);
449        return _get_zval_ptr_ptr_var(node->var, execute_data, should_free TSRMLS_CC);
450    }
451}
452
453static zend_always_inline zval *_get_obj_zval_ptr_unused(TSRMLS_D)
454{
455    if (EXPECTED(Z_OBJ(EG(This)) != NULL)) {
456        return &EG(This);
457    } else {
458        zend_error_noreturn(E_ERROR, "Using $this when not in object context");
459        return NULL;
460    }
461}
462
463static inline zval *_get_obj_zval_ptr(int op_type, znode_op *op, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
464{
465    if (op_type == IS_UNUSED) {
466        if (EXPECTED(Z_OBJ(EG(This)) != NULL)) {
467            should_free->var = NULL;
468            return &EG(This);
469        } else {
470            zend_error_noreturn(E_ERROR, "Using $this when not in object context");
471        }
472    }
473    return get_zval_ptr(op_type, op, execute_data, should_free, type);
474}
475
476static inline zval *_get_obj_zval_ptr_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
477{
478    if (op_type == IS_UNUSED) {
479        if (EXPECTED(Z_OBJ(EG(This)) != NULL)) {
480            should_free->var = NULL;
481            return &EG(This);
482        } else {
483            zend_error_noreturn(E_ERROR, "Using $this when not in object context");
484        }
485    }
486    return get_zval_ptr_ptr(op_type, node, execute_data, should_free, type);
487}
488
489static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr TSRMLS_DC)
490{
491    if (EXPECTED(variable_ptr != value_ptr)) {
492        ZVAL_MAKE_REF(value_ptr);
493        Z_ADDREF_P(value_ptr);
494        zval_ptr_dtor(variable_ptr);
495        ZVAL_REF(variable_ptr, Z_REF_P(value_ptr));
496    } else {
497        ZVAL_MAKE_REF(variable_ptr);
498    }
499}
500
501/* this should modify object only if it's empty */
502static inline zval* make_real_object(zval *object_ptr TSRMLS_DC)
503{
504    zval *object = object_ptr;
505
506    ZVAL_DEREF(object);
507    if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
508        if (Z_TYPE_P(object) == IS_NULL
509            || Z_TYPE_P(object) == IS_FALSE
510            || (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) {
511            zval_ptr_dtor_nogc(object);
512            object_init(object);
513            zend_error(E_WARNING, "Creating default object from empty value");
514        }
515    }
516    return object;
517}
518
519ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, zend_ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC)
520{
521    zend_string *key;
522    ALLOCA_FLAG(use_heap);
523
524    STR_ALLOCA_INIT(key, cur_arg_info->class_name, cur_arg_info->class_name_len, use_heap);
525    *pce = zend_fetch_class(key, (fetch_type | ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);
526    STR_ALLOCA_FREE(key, use_heap);
527
528    *class_name = (*pce) ? (*pce)->name->val : (char*)cur_arg_info->class_name;
529    if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
530        return "implement interface ";
531    } else {
532        return "be an instance of ";
533    }
534}
535
536ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC)
537{
538    zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
539    const char *fname = zf->common.function_name->val;
540    const char *fsep;
541    const char *fclass;
542    zval old_arg;
543
544    if (zf->common.scope) {
545        fsep =  "::";
546        fclass = zf->common.scope->name->val;
547    } else {
548        fsep =  "";
549        fclass = "";
550    }
551
552    if (arg && zf->common.type == ZEND_USER_FUNCTION) {
553        ZVAL_COPY_VALUE(&old_arg, arg);
554        ZVAL_UNDEF(arg);
555    }
556
557    if (zf->common.type == ZEND_USER_FUNCTION && ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
558        zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno);
559    } else {
560        zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
561    }
562
563    if (arg && zf->common.type == ZEND_USER_FUNCTION) {
564        ZVAL_COPY_VALUE(arg, &old_arg);
565    }
566}
567
568static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zend_ulong fetch_type TSRMLS_DC)
569{
570    zend_arg_info *cur_arg_info;
571    char *need_msg;
572    zend_class_entry *ce;
573
574    if (UNEXPECTED(!zf->common.arg_info)) {
575        return;
576    }
577
578    if (EXPECTED(arg_num <= zf->common.num_args)) {
579        cur_arg_info = &zf->common.arg_info[arg_num-1];
580    } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
581        cur_arg_info = &zf->common.arg_info[zf->common.num_args-1];
582    } else {
583        return;
584    }
585
586    if (cur_arg_info->class_name) {
587        char *class_name;
588
589        ZVAL_DEREF(arg);
590        if (Z_TYPE_P(arg) == IS_OBJECT) {
591            need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
592            if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
593                zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC);
594            }
595        } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
596            need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
597            zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC);
598        }
599    } else if (cur_arg_info->type_hint) {
600        if (cur_arg_info->type_hint == IS_ARRAY) {
601            ZVAL_DEREF(arg);
602            if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
603                zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
604            }
605        } else if (cur_arg_info->type_hint == IS_CALLABLE) {
606            if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
607                zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
608            }
609#if ZEND_DEBUG
610        } else {
611            zend_error(E_ERROR, "Unknown typehint");
612#endif
613        }
614    }
615}
616
617static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num, zend_ulong fetch_type TSRMLS_DC)
618{
619    zend_arg_info *cur_arg_info;
620    char *need_msg;
621    zend_class_entry *ce;
622
623    if (UNEXPECTED(!zf->common.arg_info)) {
624        return 1;
625    }
626
627    if (EXPECTED(arg_num <= zf->common.num_args)) {
628        cur_arg_info = &zf->common.arg_info[arg_num-1];
629    } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
630        cur_arg_info = &zf->common.arg_info[zf->common.num_args-1];
631    } else {
632        return 1;
633    }
634
635    if (cur_arg_info->class_name) {
636        char *class_name;
637
638        need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
639        zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC);
640    } else if (cur_arg_info->type_hint) {
641        if (cur_arg_info->type_hint == IS_ARRAY) {
642            zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL TSRMLS_CC);
643        } else if (cur_arg_info->type_hint == IS_CALLABLE) {
644            zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "", NULL TSRMLS_CC);
645#if ZEND_DEBUG
646        } else {
647            zend_error(E_ERROR, "Unknown typehint");
648#endif
649        }
650    }
651    return 0;
652}
653
654static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num TSRMLS_DC)
655{
656    if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
657        zend_verify_missing_arg_type(EX(func), arg_num, EX(opline)->extended_value TSRMLS_CC)) {
658        const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : "";
659        const char *space = EX(func)->common.scope ? "::" : "";
660        const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main";
661        zend_execute_data *ptr = EX(prev_execute_data);
662
663        if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
664            zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->func->op_array.filename->val, ptr->opline->lineno);
665        } else {
666            zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name);
667        }
668    }
669}
670
671static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *property_name, int value_type, const znode_op *value_op, const zend_execute_data *execute_data, int opcode, void **cache_slot TSRMLS_DC)
672{
673    zend_free_op free_value;
674    zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R);
675    zval tmp;
676    zval *object = object_ptr;
677
678    ZVAL_DEREF(object);
679    if (Z_TYPE_P(object) != IS_OBJECT) {
680        if (object == &EG(error_zval)) {
681            if (retval) {
682                ZVAL_NULL(retval);
683            }
684            FREE_OP(free_value);
685            return;
686        }
687        if (Z_TYPE_P(object) == IS_NULL ||
688            Z_TYPE_P(object) == IS_FALSE ||
689            (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) {
690            zend_object *obj;
691
692            zval_ptr_dtor(object);
693            object_init(object);
694            Z_ADDREF_P(object);
695            obj = Z_OBJ_P(object);
696            zend_error(E_WARNING, "Creating default object from empty value");
697            if (GC_REFCOUNT(obj) == 1) {
698                /* the enclosing container was deleted, obj is unreferenced */
699                if (retval) {
700                    ZVAL_NULL(retval);
701                }
702                FREE_OP(free_value);
703                OBJ_RELEASE(obj);
704                return;
705            }
706            Z_DELREF_P(object);
707        } else {
708            zend_error(E_WARNING, "Attempt to assign property of non-object");
709            if (retval) {
710                ZVAL_NULL(retval);
711            }
712            FREE_OP(free_value);
713            return;
714        }
715    }
716
717    /* separate our value if necessary */
718    if (value_type == IS_TMP_VAR) {
719        ZVAL_COPY_VALUE(&tmp, value);
720        value = &tmp;
721    } else if (value_type == IS_CONST) {
722        if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
723            ZVAL_COPY_VALUE(&tmp, value);
724            zval_copy_ctor_func(&tmp);
725            value = &tmp;
726        }
727    } else if (Z_REFCOUNTED_P(value)) {
728        Z_ADDREF_P(value);
729    }
730
731    if (opcode == ZEND_ASSIGN_OBJ) {
732        if (!Z_OBJ_HT_P(object)->write_property) {
733            zend_error(E_WARNING, "Attempt to assign property of non-object");
734            if (retval) {
735                ZVAL_NULL(retval);
736            }
737            if (value_type == IS_CONST) {
738                zval_ptr_dtor(value);
739            }
740            FREE_OP(free_value);
741            return;
742        }
743        Z_OBJ_HT_P(object)->write_property(object, property_name, value, cache_slot TSRMLS_CC);
744    } else {
745        /* Note:  property_name in this case is really the array index! */
746        if (!Z_OBJ_HT_P(object)->write_dimension) {
747            zend_error_noreturn(E_ERROR, "Cannot use object as array");
748        }
749        Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC);
750    }
751
752    if (retval && !EG(exception)) {
753        ZVAL_COPY(retval, value);
754    }
755    zval_ptr_dtor(value);
756    FREE_OP_IF_VAR(free_value);
757}
758
759static void zend_assign_to_string_offset(zval *str_offset, zval *value, int value_type, zval *result TSRMLS_DC)
760{
761    zval *str = Z_STR_OFFSET_STR_P(str_offset);
762    /* XXX String offset is uint32_t in _zval_struct, so can address only 2^32+1 space.
763        To make the offset get over that barier, we need to make str_offset size_t and that
764        would grow zval size by 8 bytes (currently from 16 to 24) on 64 bit build. */
765    uint32_t offset = Z_STR_OFFSET_IDX_P(str_offset);
766    zend_string *old_str;
767
768    if ((int)offset < 0) {
769        zend_error(E_WARNING, "Illegal string offset:  %d", offset);
770        zend_string_release(Z_STR_P(str));
771        if (result) {
772            ZVAL_NULL(result);
773        }
774        return;
775    }
776
777    old_str = Z_STR_P(str);
778    if (offset >= Z_STRLEN_P(str)) {
779        int old_len = Z_STRLEN_P(str);
780        Z_STR_P(str) = zend_string_realloc(Z_STR_P(str), offset + 1, 0);
781        Z_TYPE_INFO_P(str) = IS_STRING_EX;
782        memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
783        Z_STRVAL_P(str)[offset+1] = 0;
784    } else if (IS_INTERNED(Z_STR_P(str))) {
785        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
786        Z_TYPE_INFO_P(str) = IS_STRING_EX;
787    }
788
789    if (Z_TYPE_P(value) != IS_STRING) {
790        zend_string *tmp = zval_get_string(value);
791
792        Z_STRVAL_P(str)[offset] = tmp->val[0];
793        zend_string_release(tmp);
794    } else {
795        Z_STRVAL_P(str)[offset] = Z_STRVAL_P(value)[0];
796        if (value_type == IS_TMP_VAR) {
797            /* we can safely free final_value here
798             * because separation is done only
799             * in case value_type == IS_VAR */
800            zval_dtor(value);
801        }
802    }
803    /*
804     * the value of an assignment to a string offset is undefined
805    T(result->u.var).var = &T->str_offset.str;
806    */
807
808    zend_string_release(old_str);
809    if (result) {
810        zend_uchar c = (zend_uchar)Z_STRVAL_P(str)[offset];
811
812        if (CG(one_char_string)[c]) {
813            ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
814        } else {
815            ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(str) + offset, 1, 0));
816        }
817    }
818}
819
820static inline zval* zend_assign_tmp_to_variable(zval *variable_ptr, zval *value TSRMLS_DC)
821{
822    ZVAL_DEREF(variable_ptr);
823
824    if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
825        zend_refcounted *garbage;
826
827        if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
828            UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
829            Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
830            return variable_ptr;
831        }
832
833        garbage = Z_COUNTED_P(variable_ptr);
834        if (UNEXPECTED(GC_REFCOUNT(garbage) > 1)) {
835            /* we need to split */
836            GC_REFCOUNT(garbage)--;
837            /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
838            if ((Z_COLLECTABLE_P(variable_ptr)) &&
839                UNEXPECTED(!GC_INFO(garbage))) {
840                gc_possible_root(garbage TSRMLS_CC);
841            }
842        } else {
843            ZVAL_COPY_VALUE(variable_ptr, value);
844            _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
845            return variable_ptr;
846        }
847    }
848
849    ZVAL_COPY_VALUE(variable_ptr, value);
850
851    return variable_ptr;
852}
853
854static inline zval* zend_assign_const_to_variable(zval *variable_ptr, zval *value TSRMLS_DC)
855{
856    ZVAL_DEREF(variable_ptr);
857
858    if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
859        zend_refcounted *garbage;
860
861        if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
862            UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
863            Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
864            return variable_ptr;
865        }
866
867        garbage = Z_COUNTED_P(variable_ptr);
868        if (UNEXPECTED(GC_REFCOUNT(garbage) > 1)) {
869            /* we need to split */
870            GC_REFCOUNT(garbage)--;
871            /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
872            if (Z_COLLECTABLE_P(variable_ptr) &&
873                UNEXPECTED(!GC_INFO(garbage))) {
874                gc_possible_root(garbage TSRMLS_CC);
875            }
876        } else {
877            ZVAL_COPY_VALUE(variable_ptr, value);
878            /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
879            if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
880                zval_copy_ctor_func(variable_ptr);
881            }
882            _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
883            return variable_ptr;
884        }
885    }
886
887    ZVAL_COPY_VALUE(variable_ptr, value);
888    /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
889    if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
890        zval_copy_ctor_func(variable_ptr);
891    }
892
893    return variable_ptr;
894}
895
896static inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value TSRMLS_DC)
897{
898    zend_refcounted *garbage;
899
900    if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {
901        goto assign_simple;
902    } else if (UNEXPECTED(variable_ptr == value)) {
903        return variable_ptr;
904    }
905    if (Z_ISREF_P(variable_ptr)) {
906        variable_ptr = Z_REFVAL_P(variable_ptr);
907        if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {
908            goto assign_simple;
909        } else if (UNEXPECTED(variable_ptr == value)) {
910            return variable_ptr;
911        }
912    }
913
914    if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
915        UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
916        Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
917    } else {
918        if (Z_REFCOUNT_P(variable_ptr)==1) {
919            garbage = Z_COUNTED_P(variable_ptr);
920            if (UNEXPECTED(Z_REFCOUNTED_P(value))) {
921                if (EXPECTED(!Z_ISREF_P(value))) {
922                    Z_ADDREF_P(value);
923                } else {
924                    if (Z_REFCOUNT_P(value) == 1) {
925                        ZVAL_UNREF(value);
926                    } else {
927                        value = Z_REFVAL_P(value);
928                    }
929                    if (Z_REFCOUNTED_P(value)) {
930                        if (UNEXPECTED(variable_ptr == value)) {
931                            return variable_ptr;
932                        }
933                        Z_ADDREF_P(value);
934                    }
935                }
936            }
937            ZVAL_COPY_VALUE(variable_ptr, value);
938            _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
939        } else { /* we need to split */
940            Z_DELREF_P(variable_ptr);
941            GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
942assign_simple:
943            if (UNEXPECTED(Z_REFCOUNTED_P(value))) {
944                if (EXPECTED(!Z_ISREF_P(value))) {
945                    Z_ADDREF_P(value);
946                } else {
947                    if (Z_REFCOUNT_P(value) == 1) {
948                        ZVAL_UNREF(value);
949                    } else {
950                        value = Z_REFVAL_P(value);
951                    }
952                    if (Z_REFCOUNTED_P(value)) {
953                        Z_ADDREF_P(value);
954                    }
955                }
956            }
957            ZVAL_COPY_VALUE(variable_ptr, value);
958        }
959    }
960    return variable_ptr;
961}
962
963/* Utility Functions for Extensions */
964static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
965{
966    if (extension->statement_handler) {
967        extension->statement_handler(op_array);
968    }
969}
970
971
972static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
973{
974    if (extension->fcall_begin_handler) {
975        extension->fcall_begin_handler(op_array);
976    }
977}
978
979
980static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
981{
982    if (extension->fcall_end_handler) {
983        extension->fcall_end_handler(op_array);
984    }
985}
986
987
988static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_data *execute_data, int fetch_type TSRMLS_DC)
989{
990    HashTable *ht;
991
992    if (EXPECTED(fetch_type == ZEND_FETCH_GLOBAL_LOCK) ||
993        EXPECTED(fetch_type == ZEND_FETCH_GLOBAL)) {
994        ht = &EG(symbol_table).ht;
995    } else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
996        ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
997        ht = EX(func)->op_array.static_variables;
998    } else {
999        ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
1000        if (!EX(symbol_table)) {
1001            zend_rebuild_symbol_table(TSRMLS_C);
1002        }
1003        ht = &EX(symbol_table)->ht;
1004    }
1005    return ht;
1006}
1007
1008static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type TSRMLS_DC)
1009{
1010    zval *retval;
1011    zend_string *offset_key;
1012    zend_ulong hval;
1013
1014    if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
1015        hval = Z_LVAL_P(dim);
1016num_index:
1017        retval = zend_hash_index_find(ht, hval);
1018        if (retval == NULL) {
1019            switch (type) {
1020                case BP_VAR_R:
1021                    zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, hval);
1022                    /* break missing intentionally */
1023                case BP_VAR_UNSET:
1024                case BP_VAR_IS:
1025                    retval = &EG(uninitialized_zval);
1026                    break;
1027                case BP_VAR_RW:
1028                    zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, hval);
1029                    /* break missing intentionally */
1030                case BP_VAR_W:
1031                    retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
1032                    break;
1033            }
1034        }
1035    } else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
1036        offset_key = Z_STR_P(dim);
1037        if (dim_type != IS_CONST) {
1038            if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
1039                goto num_index;
1040            }
1041        }
1042str_index:
1043        retval = zend_hash_find(ht, offset_key);
1044        if (retval) {
1045            /* support for $GLOBALS[...] */
1046            if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
1047                retval = Z_INDIRECT_P(retval);
1048                if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
1049                    switch (type) {
1050                        case BP_VAR_R:
1051                            zend_error(E_NOTICE, "Undefined index: %s", offset_key->val);
1052                            /* break missing intentionally */
1053                        case BP_VAR_UNSET:
1054                        case BP_VAR_IS:
1055                            retval = &EG(uninitialized_zval);
1056                            break;
1057                        case BP_VAR_RW:
1058                            zend_error(E_NOTICE,"Undefined index: %s", offset_key->val);
1059                            /* break missing intentionally */
1060                        case BP_VAR_W:
1061                            ZVAL_NULL(retval);
1062                            break;
1063                    }
1064                }
1065            }
1066        } else {
1067            switch (type) {
1068                case BP_VAR_R:
1069                    zend_error(E_NOTICE, "Undefined index: %s", offset_key->val);
1070                    /* break missing intentionally */
1071                case BP_VAR_UNSET:
1072                case BP_VAR_IS:
1073                    retval = &EG(uninitialized_zval);
1074                    break;
1075                case BP_VAR_RW:
1076                    zend_error(E_NOTICE,"Undefined index: %s", offset_key->val);
1077                    /* break missing intentionally */
1078                case BP_VAR_W:
1079                    retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
1080                    break;
1081            }
1082        }
1083    } else {
1084        switch (Z_TYPE_P(dim)) {
1085            case IS_NULL:
1086                offset_key = STR_EMPTY_ALLOC();
1087                goto str_index;
1088            case IS_DOUBLE:
1089                hval = zend_dval_to_lval(Z_DVAL_P(dim));
1090                goto num_index;
1091            case IS_RESOURCE:
1092                zend_error(E_STRICT, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
1093                hval = Z_RES_HANDLE_P(dim);
1094                goto num_index;
1095            case IS_FALSE:
1096                hval = 0;
1097                goto num_index;
1098            case IS_TRUE:
1099                hval = 1;
1100                goto num_index;
1101            default:
1102                zend_error(E_WARNING, "Illegal offset type");
1103                retval = (type == BP_VAR_W || type == BP_VAR_RW) ?
1104                    &EG(error_zval) : &EG(uninitialized_zval);
1105        }
1106    }
1107    return retval;
1108}
1109
1110static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container_ptr, zval *dim, int dim_type, int type, int is_ref TSRMLS_DC)
1111{
1112    zval *retval;
1113    zval *container = container_ptr;
1114
1115    ZVAL_DEREF(container);
1116    if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1117        SEPARATE_ARRAY(container);
1118fetch_from_array:
1119        if (dim == NULL) {
1120            retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
1121            if (retval == NULL) {
1122                zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
1123                retval = &EG(error_zval);
1124            }
1125        } else {
1126            retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
1127        }
1128        if (is_ref) {
1129            ZVAL_MAKE_REF(retval);
1130            Z_ADDREF_P(retval);
1131            ZVAL_REF(result, Z_REF_P(retval));
1132        } else {
1133            ZVAL_INDIRECT(result, retval);
1134        }
1135    } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1136        zend_long offset;
1137
1138        if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) {
1139            zval_dtor(container);
1140convert_to_array:
1141            ZVAL_NEW_ARR(container);
1142            zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
1143            goto fetch_from_array;
1144        }
1145        if (dim == NULL) {
1146            zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
1147        }
1148
1149        if (type != BP_VAR_UNSET) {
1150            SEPARATE_STRING(container);
1151        }
1152
1153        if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1154            switch(Z_TYPE_P(dim)) {
1155                case IS_STRING:
1156                    if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1157                        break;
1158                    }
1159                    if (type != BP_VAR_UNSET) {
1160                        zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1161                    }
1162                    break;
1163                case IS_DOUBLE:
1164                case IS_NULL:
1165                case IS_FALSE:
1166                case IS_TRUE:
1167                    zend_error(E_NOTICE, "String offset cast occurred");
1168                    break;
1169                default:
1170                    zend_error(E_WARNING, "Illegal offset type");
1171                    break;
1172            }
1173
1174            offset = zval_get_long(dim);
1175        } else {
1176            offset = Z_LVAL_P(dim);
1177        }
1178
1179        if (!IS_INTERNED(Z_STR_P(container))) zend_string_addref(Z_STR_P(container));
1180        ZVAL_STR_OFFSET(result, container, offset);
1181    } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1182        if (!Z_OBJ_HT_P(container)->read_dimension) {
1183            zend_error_noreturn(E_ERROR, "Cannot use object as array");
1184        } else {
1185            retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result TSRMLS_CC);
1186
1187            if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
1188                zend_class_entry *ce = Z_OBJCE_P(container);
1189
1190                ZVAL_NULL(result);
1191                zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name->val);
1192            } else if (retval && Z_TYPE_P(retval) != IS_UNDEF) {
1193                if (!Z_ISREF_P(retval)) {
1194                    if (Z_REFCOUNTED_P(retval) &&
1195                        Z_REFCOUNT_P(retval) > 1) {
1196                        if (Z_TYPE_P(retval) != IS_OBJECT) {
1197                            Z_DELREF_P(retval);
1198                            ZVAL_DUP(result, retval);
1199                            retval = result;
1200                        } else {
1201                            ZVAL_COPY(result, retval);
1202                            retval = result;
1203                        }
1204                    }
1205                    if (Z_TYPE_P(retval) != IS_OBJECT) {
1206                        zend_class_entry *ce = Z_OBJCE_P(container);
1207                        zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name->val);
1208                    }
1209                }
1210                if (result != retval) {
1211                    if (is_ref) {
1212                        ZVAL_MAKE_REF(retval);
1213                        Z_ADDREF_P(retval);
1214                        ZVAL_REF(result, Z_REF_P(retval));
1215                    } else {
1216                        ZVAL_INDIRECT(result, retval);
1217                    }
1218                }
1219            } else {
1220                ZVAL_INDIRECT(result, &EG(error_zval));
1221            }
1222        }
1223    } else if (EXPECTED(Z_TYPE_P(container) == IS_NULL)) {
1224        if (container == &EG(error_zval)) {
1225            ZVAL_INDIRECT(result, &EG(error_zval));
1226        } else if (type != BP_VAR_UNSET) {
1227            goto convert_to_array;
1228        } else {
1229            /* for read-mode only */
1230            ZVAL_NULL(result);
1231        }
1232    } else {
1233        if (type != BP_VAR_UNSET &&
1234            Z_TYPE_P(container) == IS_FALSE) {
1235            goto convert_to_array;
1236        }
1237        if (type == BP_VAR_UNSET) {
1238            zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1239            ZVAL_NULL(result);
1240        } else {
1241            zend_error(E_WARNING, "Cannot use a scalar value as an array");
1242            ZVAL_INDIRECT(result, &EG(error_zval));
1243        }
1244    }
1245}
1246
1247static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
1248{
1249    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0 TSRMLS_CC);
1250}
1251
1252static zend_never_inline void zend_fetch_dimension_address_W_ref(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
1253{
1254    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 1 TSRMLS_CC);
1255}
1256
1257static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
1258{
1259    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW, 0 TSRMLS_CC);
1260}
1261
1262static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC)
1263{
1264    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET, 0 TSRMLS_CC);
1265}
1266
1267static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type TSRMLS_DC)
1268{
1269    zval *retval;
1270
1271    ZVAL_DEREF(container);
1272    if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1273        retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
1274        ZVAL_COPY(result, retval);
1275    } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1276        zend_long offset;
1277
1278        if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1279            switch(Z_TYPE_P(dim)) {
1280                /* case IS_LONG: */
1281                case IS_STRING:
1282                    if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1283                        break;
1284                    }
1285                    if (type != BP_VAR_IS) {
1286                        zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1287                    }
1288                    break;
1289                case IS_DOUBLE:
1290                case IS_NULL:
1291                case IS_FALSE:
1292                case IS_TRUE:
1293                    if (type != BP_VAR_IS) {
1294                        zend_error(E_NOTICE, "String offset cast occurred");
1295                    }
1296                    break;
1297                default:
1298                    zend_error(E_WARNING, "Illegal offset type");
1299                    break;
1300            }
1301
1302            offset = zval_get_long(dim);
1303        } else {
1304            offset = Z_LVAL_P(dim);
1305        }
1306
1307        if (UNEXPECTED(offset < 0) || UNEXPECTED(Z_STRLEN_P(container) <= offset)) {
1308            if (type != BP_VAR_IS) {
1309                zend_error(E_NOTICE, "Uninitialized string offset: %ld", offset);
1310            }
1311            ZVAL_EMPTY_STRING(result);
1312        } else {
1313            zend_uchar c = (zend_uchar)Z_STRVAL_P(container)[offset];
1314
1315            if (CG(one_char_string)[c]) {
1316                ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
1317            } else {
1318                ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + offset, 1, 0));
1319            }
1320        }
1321    } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1322        if (!Z_OBJ_HT_P(container)->read_dimension) {
1323            zend_error_noreturn(E_ERROR, "Cannot use object as array");
1324        } else {
1325            retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result TSRMLS_CC);
1326
1327            if (result) {
1328                if (retval) {
1329                    if (result != retval) {
1330                        ZVAL_COPY(result, retval);
1331                    }
1332                } else {
1333                    ZVAL_NULL(result);
1334                }
1335            }
1336        }
1337    } else {
1338        ZVAL_NULL(result);
1339    }
1340}
1341
1342static zend_never_inline void zend_fetch_dimension_address_read_R(zval *result, zval *container, zval *dim, int dim_type TSRMLS_DC)
1343{
1344    zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R TSRMLS_CC);
1345}
1346
1347static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zval *container, zval *dim, int dim_type TSRMLS_DC)
1348{
1349    zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS TSRMLS_CC);
1350}
1351
1352ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim TSRMLS_DC)
1353{
1354    zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR TSRMLS_CC);
1355}
1356
1357static void zend_fetch_property_address(zval *result, zval *container_ptr, zval *prop_ptr, void **cache_slot, int type, int is_ref TSRMLS_DC)
1358{
1359    zval *container = container_ptr;
1360
1361    ZVAL_DEREF(container);
1362    if (Z_TYPE_P(container) != IS_OBJECT) {
1363        if (container == &EG(error_zval)) {
1364            ZVAL_INDIRECT(result, &EG(error_zval));
1365            return;
1366        }
1367
1368        /* this should modify object only if it's empty */
1369        if (type != BP_VAR_UNSET &&
1370            ((Z_TYPE_P(container) == IS_NULL ||
1371              Z_TYPE_P(container) == IS_FALSE ||
1372              (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0)))) {
1373            zval_ptr_dtor_nogc(container);
1374            object_init(container);
1375        } else {
1376            zend_error(E_WARNING, "Attempt to modify property of non-object");
1377            ZVAL_INDIRECT(result, &EG(error_zval));
1378            return;
1379        }
1380    }
1381
1382    if (Z_OBJ_HT_P(container)->get_property_ptr_ptr) {
1383        zval *ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, type, cache_slot TSRMLS_CC);
1384        if (NULL == ptr) {
1385            if (Z_OBJ_HT_P(container)->read_property &&
1386                (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result TSRMLS_CC)) != NULL) {
1387                if (ptr != result) {
1388                    if (is_ref && ptr != &EG(uninitialized_zval)) {
1389                        ZVAL_MAKE_REF(ptr);
1390                        Z_ADDREF_P(ptr);
1391                        ZVAL_REF(result, Z_REF_P(ptr));
1392                    } else {
1393                        ZVAL_INDIRECT(result, ptr);
1394                    }
1395                }
1396            } else {
1397                zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access");
1398            }
1399        } else {
1400            if (is_ref) {
1401                ZVAL_MAKE_REF(ptr);
1402                Z_ADDREF_P(ptr);
1403                ZVAL_REF(result, Z_REF_P(ptr));
1404            } else {
1405                ZVAL_INDIRECT(result, ptr);
1406            }
1407        }
1408    } else if (Z_OBJ_HT_P(container)->read_property) {
1409        zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result TSRMLS_CC);
1410        if (ptr != result) {
1411            if (is_ref && ptr != &EG(uninitialized_zval)) {
1412                ZVAL_MAKE_REF(ptr);
1413                Z_ADDREF_P(ptr);
1414                ZVAL_REF(result, Z_REF_P(ptr));
1415            } else {
1416                ZVAL_INDIRECT(result, ptr);
1417            }
1418        }
1419    } else {
1420        zend_error(E_WARNING, "This object doesn't support property references");
1421        ZVAL_INDIRECT(result, &EG(error_zval));
1422    }
1423}
1424
1425static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_offset, const zend_op_array *op_array, const zend_execute_data *execute_data TSRMLS_DC)
1426{
1427    int original_nest_levels = nest_levels;
1428    zend_brk_cont_element *jmp_to;
1429
1430    do {
1431        if (array_offset==-1) {
1432            zend_error_noreturn(E_ERROR, "Cannot break/continue %d level%s", original_nest_levels, (original_nest_levels == 1) ? "" : "s");
1433        }
1434        jmp_to = &op_array->brk_cont_array[array_offset];
1435        if (nest_levels>1) {
1436            zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
1437
1438            if (brk_opline->opcode == ZEND_SWITCH_FREE) {
1439                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
1440                    zval_ptr_dtor(EX_VAR(brk_opline->op1.var));
1441                }
1442            } else if (brk_opline->opcode == ZEND_FREE) {
1443                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
1444                    zval_dtor(EX_VAR(brk_opline->op1.var));
1445                }
1446            }
1447        }
1448        array_offset = jmp_to->parent;
1449    } while (--nest_levels > 0);
1450    return jmp_to;
1451}
1452
1453#if ZEND_INTENSIVE_DEBUGGING
1454
1455#define CHECK_SYMBOL_TABLES()                                                   \
1456    zend_hash_apply(&EG(symbol_table), zend_check_symbol TSRMLS_CC);            \
1457    if (&EG(symbol_table)!=EX(symbol_table)) {                          \
1458        zend_hash_apply(EX(symbol_table), zend_check_symbol TSRMLS_CC); \
1459    }
1460
1461static int zend_check_symbol(zval *pz TSRMLS_DC)
1462{
1463    if (Z_TYPE_P(pz) == IS_INDIRECT) {
1464        pz = Z_INDIRECT_P(pz);
1465    }
1466    if (Z_TYPE_P(pz) > 10) {
1467        fprintf(stderr, "Warning!  %x has invalid type!\n", *pz);
1468/* See http://support.microsoft.com/kb/190351 */
1469#ifdef PHP_WIN32
1470        fflush(stderr);
1471#endif
1472    } else if (Z_TYPE_P(pz) == IS_ARRAY) {
1473        zend_hash_apply(Z_ARRVAL_P(pz), zend_check_symbol TSRMLS_CC);
1474    } else if (Z_TYPE_P(pz) == IS_OBJECT) {
1475        /* OBJ-TBI - doesn't support new object model! */
1476        zend_hash_apply(Z_OBJPROP_P(pz), zend_check_symbol TSRMLS_CC);
1477    }
1478
1479    return 0;
1480}
1481
1482
1483#else
1484#define CHECK_SYMBOL_TABLES()
1485#endif
1486
1487ZEND_API opcode_handler_t *zend_opcode_handlers;
1488
1489ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value TSRMLS_DC)
1490{
1491    execute_data->func->internal_function.handler(execute_data->num_args, return_value TSRMLS_CC);
1492}
1493
1494void zend_clean_and_cache_symbol_table(zend_array *symbol_table TSRMLS_DC) /* {{{ */
1495{
1496    if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
1497        zend_hash_destroy(&symbol_table->ht);
1498        FREE_HASHTABLE(symbol_table);
1499    } else {
1500        /* clean before putting into the cache, since clean
1501           could call dtors, which could use cached hash */
1502        zend_hash_clean(&symbol_table->ht);
1503        *(++EG(symtable_cache_ptr)) = symbol_table;
1504    }
1505}
1506/* }}} */
1507
1508static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
1509{
1510    if (EXPECTED(EX(func)->op_array.last_var > 0)) {
1511        zval *cv = EX_VAR_NUM(0);
1512        zval *end = cv + EX(func)->op_array.last_var;
1513        do {
1514            zval_ptr_dtor(cv);
1515            cv++;
1516        } while (cv != end);
1517    }
1518}
1519/* }}} */
1520
1521void zend_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
1522{
1523    i_free_compiled_variables(execute_data TSRMLS_CC);
1524}
1525/* }}} */
1526
1527/*
1528 * Stack Frame Layout (the whole stack frame is allocated at once)
1529 * ==================
1530 *
1531 *                             +========================================+
1532 * EG(current_execute_data) -> | zend_execute_data                      |
1533 *                             +----------------------------------------+
1534 *     EX_CV_NUM(0) ---------> | VAR[0] = ARG[1]                        |
1535 *                             | ...                                    |
1536 *                             | VAR[op_array->num_args-1] = ARG[N]     |
1537 *                             | ...                                    |
1538 *                             | VAR[op_array->last_var-1]              |
1539 *                             | VAR[op_array->last_var] = TMP[0]       |
1540 *                             | ...                                    |
1541 *                             | VAR[op_array->last_var+op_array->T-1]  |
1542 *                             | ARG[N+1] (extra_args)                  |
1543 *                             | ...                                    |
1544 *                             +----------------------------------------+
1545 */
1546
1547static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
1548{
1549    uint32_t first_extra_arg;
1550    ZEND_ASSERT(EX(func) == (zend_function*)op_array);
1551    ZEND_ASSERT(EX(object) == Z_OBJ(EG(This)));
1552
1553    EX(return_value) = return_value;
1554    EX(frame_kind) = frame_kind;
1555    ZVAL_UNDEF(&EX(old_error_reporting));
1556    EX(delayed_exception) = NULL;
1557    EX(call) = NULL;
1558
1559    EX(opline) = op_array->opcodes;
1560    if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
1561        /* Skip useless ZEND_RECV opcodes */
1562        EX(opline) += MIN(EX(num_args), op_array->required_num_args);
1563    }
1564    EX(scope) = EG(scope);
1565
1566    first_extra_arg = op_array->num_args;
1567
1568    if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) {
1569        first_extra_arg--;
1570    }
1571    if (UNEXPECTED(EX(num_args) > first_extra_arg)) {
1572        /* move extra args into separate array after all CV and TMP vars */
1573        zval *extra_args = EX_VAR_NUM(op_array->last_var + op_array->T);
1574
1575        memmove(extra_args, EX_VAR_NUM(first_extra_arg), sizeof(zval) * (EX(num_args) - first_extra_arg));
1576    }
1577
1578    do {
1579        /* Initialize CV variables (skip arguments) */
1580        int num_args = MIN(op_array->num_args, EX(num_args));
1581
1582        if (EXPECTED(num_args < op_array->last_var)) {
1583            zval *var = EX_VAR_NUM(num_args);
1584            zval *end = EX_VAR_NUM(op_array->last_var);
1585
1586            do {
1587                ZVAL_UNDEF(var);
1588                var++;
1589            } while (var != end);
1590        }
1591    } while (0);
1592
1593    if (op_array->this_var != -1 && EX(object)) {
1594        ZVAL_OBJ(EX_VAR(op_array->this_var), EX(object));
1595        GC_REFCOUNT(EX(object))++;
1596    }
1597
1598    if (!op_array->run_time_cache && op_array->last_cache_slot) {
1599        if (op_array->function_name) {
1600            op_array->run_time_cache = zend_arena_calloc(&CG(arena), op_array->last_cache_slot, sizeof(void*));
1601        } else {
1602            op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
1603        }
1604    }
1605    EX(run_time_cache) = op_array->run_time_cache;
1606
1607    EG(current_execute_data) = execute_data;
1608}
1609/* }}} */
1610
1611static zend_always_inline void i_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
1612{
1613    ZEND_ASSERT(EX(func) == (zend_function*)op_array);
1614    ZEND_ASSERT(EX(object) == Z_OBJ(EG(This)));
1615
1616    EX(return_value) = return_value;
1617    EX(frame_kind) = frame_kind;
1618    ZVAL_UNDEF(&EX(old_error_reporting));
1619    EX(delayed_exception) = NULL;
1620    EX(call) = NULL;
1621
1622    EX(opline) = op_array->opcodes;
1623    EX(scope) = EG(scope);
1624
1625    zend_attach_symbol_table(execute_data);
1626
1627    if (!op_array->run_time_cache && op_array->last_cache_slot) {
1628        if (op_array->function_name) {
1629            op_array->run_time_cache = zend_arena_calloc(&CG(arena), op_array->last_cache_slot, sizeof(void*));
1630        } else {
1631            op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
1632        }
1633    }
1634    EX(run_time_cache) = op_array->run_time_cache;
1635
1636    EG(current_execute_data) = execute_data;
1637}
1638/* }}} */
1639
1640static zend_always_inline void i_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
1641{
1642    ZEND_ASSERT(EX(func) == (zend_function*)op_array);
1643    ZEND_ASSERT(EX(object) == Z_OBJ(EG(This)));
1644
1645    EX(return_value) = return_value;
1646    EX(frame_kind) = frame_kind;
1647    ZVAL_UNDEF(&EX(old_error_reporting));
1648    EX(delayed_exception) = NULL;
1649    EX(call) = NULL;
1650
1651    EX(opline) = op_array->opcodes;
1652    EX(scope) = EG(scope);
1653
1654    if (UNEXPECTED(EX(symbol_table) != NULL)) {
1655        zend_attach_symbol_table(execute_data);
1656    } else {
1657        uint32_t first_extra_arg = op_array->num_args;
1658
1659        if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) {
1660            first_extra_arg--;
1661        }
1662        if (UNEXPECTED(EX(num_args) > first_extra_arg)) {
1663            /* move extra args into separate array after all CV and TMP vars */
1664            zval *extra_args = EX_VAR_NUM(op_array->last_var + op_array->T);
1665
1666            memmove(extra_args, EX_VAR_NUM(first_extra_arg), sizeof(zval) * (EX(num_args) - first_extra_arg));
1667        }
1668
1669        do {
1670            /* Initialize CV variables (skip arguments) */
1671            int num_args = MIN(op_array->num_args, EX(num_args));
1672
1673            if (EXPECTED(num_args < op_array->last_var)) {
1674                zval *var = EX_VAR_NUM(num_args);
1675                zval *end = EX_VAR_NUM(op_array->last_var);
1676
1677                do {
1678                    ZVAL_UNDEF(var);
1679                    var++;
1680                } while (var != end);
1681            }
1682        } while (0);
1683
1684        if (op_array->this_var != -1 && EX(object)) {
1685            ZVAL_OBJ(EX_VAR(op_array->this_var), EX(object));
1686            GC_REFCOUNT(EX(object))++;
1687        }
1688    }
1689
1690    if (!op_array->run_time_cache && op_array->last_cache_slot) {
1691        if (op_array->function_name) {
1692            op_array->run_time_cache = zend_arena_calloc(&CG(arena), op_array->last_cache_slot, sizeof(void*));
1693        } else {
1694            op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
1695        }
1696    }
1697    EX(run_time_cache) = op_array->run_time_cache;
1698
1699    EG(current_execute_data) = execute_data;
1700}
1701/* }}} */
1702
1703ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value TSRMLS_DC) /* {{{ */
1704{
1705    /*
1706     * Normally the execute_data is allocated on the VM stack (because it does
1707     * not actually do any allocation and thus is faster). For generators
1708     * though this behavior would be suboptimal, because the (rather large)
1709     * structure would have to be copied back and forth every time execution is
1710     * suspended or resumed. That's why for generators the execution context
1711     * is allocated using a separate VM stack, thus allowing to save and
1712     * restore it simply by replacing a pointer.
1713     */
1714    zend_execute_data *execute_data;
1715    uint32_t num_args = call->num_args;
1716
1717    EG(argument_stack) = zend_vm_stack_new_page(
1718        MAX(ZEND_VM_STACK_PAGE_SIZE,
1719            ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)));
1720    EG(argument_stack)->prev = NULL;
1721
1722    execute_data = zend_vm_stack_push_call_frame(
1723        (zend_function*)op_array,
1724        num_args,
1725        call->flags,
1726        call->called_scope,
1727        call->object,
1728        NULL TSRMLS_CC);
1729    EX(num_args) = num_args;
1730
1731    /* copy arguments */
1732    if (num_args > 0) {
1733        zval *arg_src = ZEND_CALL_ARG(call, 1);
1734        zval *arg_dst = ZEND_CALL_ARG(execute_data, 1);
1735        int i;
1736
1737        for (i = 0; i < num_args; i++) {
1738            ZVAL_COPY_VALUE(arg_dst + i, arg_src + i);
1739        }
1740    }
1741
1742    EX(symbol_table) = NULL;
1743
1744    i_init_func_execute_data(execute_data, op_array, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC);
1745
1746    return execute_data;
1747}
1748/* }}} */
1749
1750ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
1751{
1752    EX(prev_execute_data) = EG(current_execute_data);
1753    i_init_execute_data(execute_data, op_array, return_value, frame_kind TSRMLS_CC);
1754}
1755/* }}} */
1756
1757static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(const zend_op *opline, zend_execute_data *call TSRMLS_DC) /* {{{ */
1758{
1759    uint32_t arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK;
1760    return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num);
1761}
1762/* }}} */
1763
1764static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, uint32_t passed_args, uint32_t additional_args TSRMLS_DC) /* {{{ */
1765{
1766    zend_execute_data *new_call;
1767    int used_stack = (EG(argument_stack)->top - (zval*)call) + additional_args;
1768
1769    /* copy call frame into new stack segment */
1770    zend_vm_stack_extend(used_stack TSRMLS_CC);
1771    new_call = (zend_execute_data*)EG(argument_stack)->top;
1772    EG(argument_stack)->top += used_stack;
1773    *new_call = *call;
1774    if (passed_args) {
1775        zval *src = ZEND_CALL_ARG(call, 1);
1776        zval *dst = ZEND_CALL_ARG(new_call, 1);
1777        do {
1778            ZVAL_COPY_VALUE(dst, src);
1779            passed_args--;
1780            src++;
1781            dst++;
1782        } while (passed_args);
1783    }
1784
1785    /* delete old call_frame from previous stack segment */
1786    EG(argument_stack)->prev->top = (zval*)call;
1787
1788    /* delete previous stack segment if it becames empty */
1789    if (UNEXPECTED(EG(argument_stack)->prev->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)->prev))) {
1790        zend_vm_stack r = EG(argument_stack)->prev;
1791
1792        EG(argument_stack)->prev = r->prev;
1793        efree(r);
1794    }
1795
1796    return new_call;
1797}
1798/* }}} */
1799
1800static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, uint32_t passed_args, uint32_t additional_args TSRMLS_DC) /* {{{ */
1801{
1802    if (EXPECTED(EG(argument_stack)->end - EG(argument_stack)->top > additional_args)) {
1803        EG(argument_stack)->top += additional_args;
1804    } else {
1805        *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args TSRMLS_CC);
1806    }
1807}
1808/* }}} */
1809
1810#define ZEND_VM_NEXT_OPCODE() \
1811    CHECK_SYMBOL_TABLES() \
1812    ZEND_VM_INC_OPCODE(); \
1813    ZEND_VM_CONTINUE()
1814
1815#define ZEND_VM_SET_OPCODE(new_op) \
1816    CHECK_SYMBOL_TABLES() \
1817    OPLINE = new_op
1818
1819#define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
1820    CHECK_SYMBOL_TABLES() \
1821    OPLINE = ((zend_op*)(((char*)opline)+(offset)))
1822
1823#define ZEND_VM_JMP(new_op) \
1824    if (EXPECTED(!EG(exception))) { \
1825        ZEND_VM_SET_OPCODE(new_op); \
1826    } else { \
1827        LOAD_OPLINE(); \
1828    } \
1829    ZEND_VM_CONTINUE()
1830
1831#define ZEND_VM_INC_OPCODE() \
1832    OPLINE++
1833
1834#ifdef __GNUC__
1835# define ZEND_VM_GUARD(name) __asm__("#" #name)
1836#else
1837# define ZEND_VM_GUARD(name)
1838#endif
1839
1840#include "zend_vm_execute.h"
1841
1842ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
1843{
1844    if (opcode != ZEND_USER_OPCODE) {
1845        if (handler == NULL) {
1846            /* restore the original handler */
1847            zend_user_opcodes[opcode] = opcode;
1848        } else {
1849            zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
1850        }
1851        zend_user_opcode_handlers[opcode] = handler;
1852        return SUCCESS;
1853    }
1854    return FAILURE;
1855}
1856
1857ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
1858{
1859    return zend_user_opcode_handlers[opcode];
1860}
1861
1862ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) {
1863    return get_zval_ptr(op_type, node, execute_data, should_free, type);
1864}
1865
1866/*
1867 * Local variables:
1868 * tab-width: 4
1869 * c-basic-offset: 4
1870 * indent-tabs-mode: t
1871 * End:
1872 */
1873