1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2015 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#include "zend_inheritance.h"
42
43/* Virtual current working directory support */
44#include "zend_virtual_cwd.h"
45
46#define _CONST_CODE  0
47#define _TMP_CODE    1
48#define _VAR_CODE    2
49#define _UNUSED_CODE 3
50#define _CV_CODE     4
51
52typedef int (ZEND_FASTCALL *incdec_t)(zval *);
53
54#define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type)
55#define get_zval_ptr_deref(op_type, node, ex, should_free, type) _get_zval_ptr_deref(op_type, node, ex, should_free, type)
56#define get_zval_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_undef(op_type, node, ex, should_free, type)
57#define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type)
58#define get_zval_ptr_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type)
59#define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type)
60#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)
61
62/* Prototypes */
63static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array);
64static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array);
65static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array);
66
67#define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
68
69static ZEND_FUNCTION(pass)
70{
71}
72
73static const zend_internal_function zend_pass_function = {
74    ZEND_INTERNAL_FUNCTION, /* type              */
75    {0, 0, 0},              /* arg_flags         */
76    0,                      /* fn_flags          */
77    NULL,                   /* name              */
78    NULL,                   /* scope             */
79    NULL,                   /* prototype         */
80    0,                      /* num_args          */
81    0,                      /* required_num_args */
82    NULL,                   /* arg_info          */
83    ZEND_FN(pass),          /* handler           */
84    NULL                    /* module            */
85};
86
87#undef zval_ptr_dtor
88#define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC)
89
90#define PZVAL_LOCK(z) if (Z_REFCOUNTED_P(z)) Z_ADDREF_P((z))
91#define SELECTIVE_PZVAL_LOCK(pzv, opline)   if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }
92
93#define READY_TO_DESTROY(zv) \
94    (zv && Z_REFCOUNTED_P(zv) && Z_REFCOUNT_P(zv) == 1)
95
96#define EXTRACT_ZVAL_PTR(zv) do {                       \
97        zval *__zv = (zv);                              \
98        if (Z_TYPE_P(__zv) == IS_INDIRECT) {            \
99            ZVAL_COPY(__zv, Z_INDIRECT_P(__zv));        \
100        }                                               \
101    } while (0)
102
103#define FREE_OP(should_free) \
104    if (should_free) { \
105        zval_ptr_dtor_nogc(should_free); \
106    }
107
108#define FREE_UNFETCHED_OP(type, var) \
109    if ((type) & (IS_TMP_VAR|IS_VAR)) { \
110        zval_ptr_dtor_nogc(EX_VAR(var)); \
111    }
112
113#define FREE_OP_VAR_PTR(should_free) \
114    if (should_free) { \
115        zval_ptr_dtor_nogc(should_free); \
116    }
117
118/* End of zend_execute_locks.h */
119
120#define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
121
122#define CTOR_CALL_BIT    0x1
123#define CTOR_USED_BIT    0x2
124
125#define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
126#define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
127
128#define ENCODE_CTOR(ce, used) \
129    ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
130#define DECODE_CTOR(ce) \
131    ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
132
133#define ZEND_VM_MAIN_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
134#define ZEND_VM_GENERATOR_STACK_PAGE_SLOTS (256)
135
136#define ZEND_VM_STACK_PAGE_SLOTS(gen) ((gen) ? ZEND_VM_GENERATOR_STACK_PAGE_SLOTS : ZEND_VM_MAIN_STACK_PAGE_SLOTS)
137
138#define ZEND_VM_STACK_PAGE_SIZE(gen)  (ZEND_VM_STACK_PAGE_SLOTS(gen) * sizeof(zval))
139
140#define ZEND_VM_STACK_FREE_PAGE_SIZE(gen) \
141    ((ZEND_VM_STACK_PAGE_SLOTS(gen) - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval))
142
143#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(gen, size) \
144    (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE(gen) - 1)) & ~ZEND_VM_STACK_PAGE_SIZE(gen))
145
146static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
147    zend_vm_stack page = (zend_vm_stack)emalloc(size);
148
149    page->top = ZEND_VM_STACK_ELEMETS(page);
150    page->end = (zval*)((char*)page + size);
151    page->prev = prev;
152    return page;
153}
154
155ZEND_API void zend_vm_stack_init(void)
156{
157    EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE(0 /* main stack */), NULL);
158    EG(vm_stack)->top++;
159    EG(vm_stack_top) = EG(vm_stack)->top;
160    EG(vm_stack_end) = EG(vm_stack)->end;
161}
162
163ZEND_API void zend_vm_stack_destroy(void)
164{
165    zend_vm_stack stack = EG(vm_stack);
166
167    while (stack != NULL) {
168        zend_vm_stack p = stack->prev;
169        efree(stack);
170        stack = p;
171    }
172}
173
174ZEND_API void* zend_vm_stack_extend(size_t size)
175{
176    zend_vm_stack stack;
177    void *ptr;
178
179    stack = EG(vm_stack);
180    stack->top = EG(vm_stack_top);
181    EG(vm_stack) = stack = zend_vm_stack_new_page(
182        EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE(0)) ?
183            ZEND_VM_STACK_PAGE_SIZE(0) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(0, size),
184        stack);
185    ptr = stack->top;
186    EG(vm_stack_top) = (void*)(((char*)ptr) + size);
187    EG(vm_stack_end) = stack->end;
188    return ptr;
189}
190
191ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data, uint32_t var)
192{
193    return EX_VAR(var);
194}
195
196static zend_always_inline zval *_get_zval_ptr_tmp(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
197{
198    zval *ret = EX_VAR(var);
199    *should_free = ret;
200
201    ZEND_ASSERT(Z_TYPE_P(ret) != IS_REFERENCE);
202
203    return ret;
204}
205
206static zend_always_inline zval *_get_zval_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
207{
208    zval *ret = EX_VAR(var);
209
210    *should_free = ret;
211    return ret;
212}
213
214static zend_always_inline zval *_get_zval_ptr_var_deref(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
215{
216    zval *ret = EX_VAR(var);
217
218    *should_free = ret;
219    ZVAL_DEREF(ret);
220    return ret;
221}
222
223static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int type, const zend_execute_data *execute_data)
224{
225    zend_string *cv;
226
227    switch (type) {
228        case BP_VAR_R:
229        case BP_VAR_UNSET:
230            cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
231            zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
232            /* break missing intentionally */
233        case BP_VAR_IS:
234            ptr = &EG(uninitialized_zval);
235            break;
236        case BP_VAR_RW:
237            cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
238            zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
239            /* break missing intentionally */
240        case BP_VAR_W:
241            ZVAL_NULL(ptr);
242            break;
243    }
244    return ptr;
245}
246
247static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
248{
249    zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
250
251    zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
252    return &EG(uninitialized_zval);
253}
254
255static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
256{
257    zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
258
259    zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
260    return &EG(uninitialized_zval);
261}
262
263static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
264{
265    zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
266
267    ZVAL_NULL(ptr);
268    zend_error(E_NOTICE, "Undefined variable: %s", cv->val);
269    return ptr;
270}
271
272static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_W(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
273{
274    ZVAL_NULL(ptr);
275    return ptr;
276}
277
278static zend_always_inline zval *_get_zval_ptr_cv(const zend_execute_data *execute_data, uint32_t var, int type)
279{
280    zval *ret = EX_VAR(var);
281
282    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
283        return _get_zval_cv_lookup(ret, var, type, execute_data);
284    }
285    return ret;
286}
287
288static zend_always_inline zval *_get_zval_ptr_cv_undef(const zend_execute_data *execute_data, uint32_t var)
289{
290    return EX_VAR(var);
291}
292
293static zend_always_inline zval *_get_zval_ptr_cv_deref(const zend_execute_data *execute_data, uint32_t var, int type)
294{
295    zval *ret = EX_VAR(var);
296
297    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
298        return _get_zval_cv_lookup(ret, var, type, execute_data);
299    }
300    ZVAL_DEREF(ret);
301    return ret;
302}
303
304static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, uint32_t var)
305{
306    zval *ret = EX_VAR(var);
307
308    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
309        return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data);
310    }
311    return ret;
312}
313
314static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_R(const zend_execute_data *execute_data, uint32_t var)
315{
316    zval *ret = EX_VAR(var);
317
318    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
319        return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data);
320    }
321    ZVAL_DEREF(ret);
322    return ret;
323}
324
325static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var)
326{
327    zval *ret = EX_VAR(var);
328
329    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
330        return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data);
331    }
332    return ret;
333}
334
335static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var)
336{
337    zval *ret = EX_VAR(var);
338
339    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
340        return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data);
341    }
342    ZVAL_DEREF(ret);
343    return ret;
344}
345
346static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, uint32_t var)
347{
348    zval *ret = EX_VAR(var);
349
350    return ret;
351}
352
353static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_IS(const zend_execute_data *execute_data, uint32_t var)
354{
355    zval *ret = EX_VAR(var);
356
357    ZVAL_DEREF(ret);
358    return ret;
359}
360
361static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var)
362{
363    zval *ret = EX_VAR(var);
364
365    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
366        return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data);
367    }
368    return ret;
369}
370
371static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var)
372{
373    zval *ret = EX_VAR(var);
374
375    if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
376        return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data);
377    }
378    ZVAL_DEREF(ret);
379    return ret;
380}
381
382static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
383{
384    zval *ret = EX_VAR(var);
385
386    if (Z_TYPE_P(ret) == IS_UNDEF) {
387        return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data);
388    }
389    return ret;
390}
391
392static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
393{
394    return EX_VAR(var);
395}
396
397static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var)
398{
399    return EX_VAR(var);
400}
401
402static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
403{
404    zval *ret = EX_VAR(var);
405
406    if (Z_TYPE_P(ret) == IS_UNDEF) {
407        return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data);
408    }
409    ZVAL_DEREF(ret);
410    return ret;
411}
412
413static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
414{
415    if (op_type & (IS_TMP_VAR|IS_VAR)) {
416        if (op_type == IS_TMP_VAR) {
417            return _get_zval_ptr_tmp(node.var, execute_data, should_free);
418        } else {
419            ZEND_ASSERT(op_type == IS_VAR);
420            return _get_zval_ptr_var(node.var, execute_data, should_free);
421        }
422    } else {
423        *should_free = NULL;
424        if (op_type == IS_CONST) {
425            return EX_CONSTANT(node);
426        } else if (op_type == IS_CV) {
427            return _get_zval_ptr_cv(execute_data, node.var, type);
428        } else {
429            return NULL;
430        }
431    }
432}
433
434static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
435{
436    if (op_type & (IS_TMP_VAR|IS_VAR)) {
437        if (op_type == IS_TMP_VAR) {
438            return _get_zval_ptr_tmp(node.var, execute_data, should_free);
439        } else {
440            ZEND_ASSERT(op_type == IS_VAR);
441            return _get_zval_ptr_var_deref(node.var, execute_data, should_free);
442        }
443    } else {
444        *should_free = NULL;
445        if (op_type == IS_CONST) {
446            return EX_CONSTANT(node);
447        } else if (op_type == IS_CV) {
448            return _get_zval_ptr_cv_deref(execute_data, node.var, type);
449        } else {
450            return NULL;
451        }
452    }
453}
454
455static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
456{
457    if (op_type & (IS_TMP_VAR|IS_VAR)) {
458        if (op_type == IS_TMP_VAR) {
459            return _get_zval_ptr_tmp(node.var, execute_data, should_free);
460        } else {
461            ZEND_ASSERT(op_type == IS_VAR);
462            return _get_zval_ptr_var(node.var, execute_data, should_free);
463        }
464    } else {
465        *should_free = NULL;
466        if (op_type == IS_CONST) {
467            return EX_CONSTANT(node);
468        } else if (op_type == IS_CV) {
469            return _get_zval_ptr_cv_undef(execute_data, node.var);
470        } else {
471            return NULL;
472        }
473    }
474}
475
476static zend_always_inline zval *_get_zval_ptr_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
477{
478    zval *ret = EX_VAR(var);
479
480    if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
481        *should_free = NULL;
482        ret = Z_INDIRECT_P(ret);
483    } else if (!Z_REFCOUNTED_P(ret)) {
484        *should_free = ret; /* immutable array may be converted to regular */
485    } else if (Z_REFCOUNT_P(ret) == 1) {
486        *should_free = ret;
487    } else {
488        *should_free = NULL;
489        Z_DELREF_P(ret);
490    }
491    return ret;
492}
493
494static inline zval *_get_zval_ptr_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
495{
496    if (op_type == IS_CV) {
497        *should_free = NULL;
498        return _get_zval_ptr_cv(execute_data, node.var, type);
499    } else /* if (op_type == IS_VAR) */ {
500        ZEND_ASSERT(op_type == IS_VAR);
501        return _get_zval_ptr_ptr_var(node.var, execute_data, should_free);
502    }
503}
504
505static zend_always_inline zval *_get_obj_zval_ptr_unused(zend_execute_data *execute_data)
506{
507    return &EX(This);
508}
509
510static inline zval *_get_obj_zval_ptr(int op_type, znode_op op, zend_execute_data *execute_data, zend_free_op *should_free, int type)
511{
512    if (op_type == IS_UNUSED) {
513        *should_free = NULL;
514        return &EX(This);
515    }
516    return get_zval_ptr(op_type, op, execute_data, should_free, type);
517}
518
519static inline zval *_get_obj_zval_ptr_ptr(int op_type, znode_op node, zend_execute_data *execute_data, zend_free_op *should_free, int type)
520{
521    if (op_type == IS_UNUSED) {
522        *should_free = NULL;
523        return &EX(This);
524    }
525    return get_zval_ptr_ptr(op_type, node, execute_data, should_free, type);
526}
527
528static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
529{
530    if (EXPECTED(variable_ptr != value_ptr)) {
531        zend_reference *ref;
532        ZVAL_MAKE_REF(value_ptr);
533        Z_ADDREF_P(value_ptr);
534        ref = Z_REF_P(value_ptr);
535
536        zval_ptr_dtor(variable_ptr);
537        ZVAL_REF(variable_ptr, ref);
538    } else {
539        ZVAL_MAKE_REF(variable_ptr);
540    }
541}
542
543/* this should modify object only if it's empty */
544static inline int make_real_object(zval *object)
545{
546    if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
547        if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
548            /* nothing to destroy */
549        } else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
550            zval_ptr_dtor_nogc(object);
551        } else {
552            return 0;
553        }
554        object_init(object);
555        zend_error(E_WARNING, "Creating default object from empty value");
556    }
557    return 1;
558}
559
560ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce)
561{
562    zend_string *key;
563    ALLOCA_FLAG(use_heap);
564
565    STR_ALLOCA_INIT(key, cur_arg_info->class_name, strlen(cur_arg_info->class_name), use_heap);
566    *pce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
567    STR_ALLOCA_FREE(key, use_heap);
568
569    *class_name = (*pce) ? (*pce)->name->val : (char*)cur_arg_info->class_name;
570    if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
571        return "implement interface ";
572    } else {
573        return "be an instance of ";
574    }
575}
576
577ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce)
578{
579    *pce = zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
580
581    *class_name = (*pce) ? (*pce)->name->val : cur_arg_info->class_name->val;
582    if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
583        return "implement interface ";
584    } else {
585        return "be an instance of ";
586    }
587}
588
589ZEND_API void zend_verify_arg_error(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)
590{
591    zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
592    const char *fname = zf->common.function_name->val;
593    const char *fsep;
594    const char *fclass;
595    zval old_arg;
596
597    if (zf->common.scope) {
598        fsep =  "::";
599        fclass = zf->common.scope->name->val;
600    } else {
601        fsep =  "";
602        fclass = "";
603    }
604
605    if (zf->common.type == ZEND_USER_FUNCTION) {
606        if (arg) {
607            ZVAL_COPY_VALUE(&old_arg, arg);
608            ZVAL_UNDEF(arg);
609        }
610
611        if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
612            zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d",
613                    arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind,
614                    ptr->func->op_array.filename->val, ptr->opline->lineno);
615        } else {
616            zend_type_error("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);
617        }
618
619        if (arg) {
620            ZVAL_COPY_VALUE(arg, &old_arg);
621        }
622    } else {
623        zend_type_error("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);
624    }
625}
626
627static int is_null_constant(zval *default_value)
628{
629    if (Z_CONSTANT_P(default_value)) {
630        zval constant;
631
632        ZVAL_COPY_VALUE(&constant, default_value);
633        if (UNEXPECTED(zval_update_constant_ex(&constant, 0, NULL) != SUCCESS)) {
634            return 0;
635        }
636        if (Z_TYPE(constant) == IS_NULL) {
637            return 1;
638        }
639        zval_dtor(&constant);
640    }
641    return 0;
642}
643
644static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg)
645{
646    switch (type_hint) {
647        case _IS_BOOL: {
648            zend_bool dest;
649
650            if (!zend_parse_arg_bool_weak(arg, &dest)) {
651                return 0;
652            }
653            zval_ptr_dtor(arg);
654            ZVAL_BOOL(arg, dest);
655            return 1;
656        }
657        case IS_LONG: {
658            zend_long dest;
659
660            if (!zend_parse_arg_long_weak(arg, &dest)) {
661                return 0;
662            }
663            zval_ptr_dtor(arg);
664            ZVAL_LONG(arg, dest);
665            return 1;
666        }
667        case IS_DOUBLE: {
668            double dest;
669
670            if (!zend_parse_arg_double_weak(arg, &dest)) {
671                return 0;
672            }
673            zval_ptr_dtor(arg);
674            ZVAL_DOUBLE(arg, dest);
675            return 1;
676        }
677        case IS_STRING: {
678            zend_string *dest;
679
680            /* on success "arg" is converted to IS_STRING */
681            if (!zend_parse_arg_str_weak(arg, &dest)) {
682                return 0;
683            }
684            return 1;
685        }
686        default:
687            return 0;
688    }
689}
690
691static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, zend_bool strict)
692{
693    if (UNEXPECTED(strict)) {
694        /* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
695        if (type_hint != IS_DOUBLE || Z_TYPE_P(arg) != IS_LONG) {
696            return 0;
697        }
698    } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
699        /* NULL may be accepted only by nullable hints (this is already checked) */
700        return 0;
701    }
702    return zend_verify_weak_scalar_type_hint(type_hint, arg);
703}
704
705static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg)
706{
707    zend_internal_arg_info *cur_arg_info;
708    char *need_msg, *class_name;
709    zend_class_entry *ce;
710
711    if (EXPECTED(arg_num <= zf->internal_function.num_args)) {
712        cur_arg_info = &zf->internal_function.arg_info[arg_num-1];
713    } else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) {
714        cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args];
715    } else {
716        return;
717    }
718
719    if (cur_arg_info->type_hint) {
720        ZVAL_DEREF(arg);
721        if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
722            if (cur_arg_info->class_name) {
723                need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
724                if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
725                    zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
726                }
727            }
728        } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
729            if (cur_arg_info->class_name) {
730                need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
731                zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
732            } else if (cur_arg_info->type_hint == IS_CALLABLE) {
733                if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
734                    zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
735                }
736            } else if (cur_arg_info->type_hint == _IS_BOOL &&
737                       EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
738                /* pass */
739            } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
740                zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
741            }
742        }
743    }
744}
745
746static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value)
747{
748    zend_arg_info *cur_arg_info;
749    char *need_msg, *class_name;
750    zend_class_entry *ce;
751
752    if (EXPECTED(arg_num <= zf->common.num_args)) {
753        cur_arg_info = &zf->common.arg_info[arg_num-1];
754    } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
755        cur_arg_info = &zf->common.arg_info[zf->common.num_args];
756    } else {
757        return;
758    }
759
760    if (cur_arg_info->type_hint) {
761        ZVAL_DEREF(arg);
762        if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
763            if (cur_arg_info->class_name) {
764                need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
765                if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
766                    zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
767                }
768            }
769        } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
770            if (cur_arg_info->class_name) {
771                need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
772                zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
773            } else if (cur_arg_info->type_hint == IS_CALLABLE) {
774                if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
775                    zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
776                }
777            } else if (cur_arg_info->type_hint == _IS_BOOL &&
778                       EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
779                /* pass */
780            } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_ARG_USES_STRICT_TYPES()))) {
781                zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
782            }
783        }
784    }
785}
786
787static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num)
788{
789    zend_arg_info *cur_arg_info;
790    char *need_msg;
791    zend_class_entry *ce;
792
793    if (EXPECTED(arg_num <= zf->common.num_args)) {
794        cur_arg_info = &zf->common.arg_info[arg_num-1];
795    } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
796        cur_arg_info = &zf->common.arg_info[zf->common.num_args];
797    } else {
798        return 1;
799    }
800
801    if (cur_arg_info->type_hint) {
802        if (cur_arg_info->class_name) {
803            char *class_name;
804
805            need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
806            zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "", NULL);
807            return 0;
808        } else if (cur_arg_info->type_hint == IS_CALLABLE) {
809            zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
810        } else {
811            zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL);
812        }
813        return 0;
814    }
815    return 1;
816}
817
818static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num)
819{
820    if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
821        zend_verify_missing_arg_type(EX(func), arg_num)) {
822        const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : "";
823        const char *space = EX(func)->common.scope ? "::" : "";
824        const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main";
825        zend_execute_data *ptr = EX(prev_execute_data);
826
827        if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
828            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);
829        } else {
830            zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name);
831        }
832    }
833}
834
835ZEND_API void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
836{
837    const char *fname = zf->common.function_name->val;
838    const char *fsep;
839    const char *fclass;
840
841    if (zf->common.scope) {
842        fsep =  "::";
843        fclass = zf->common.scope->name->val;
844    } else {
845        fsep =  "";
846        fclass = "";
847    }
848
849    if (zf->common.type == ZEND_USER_FUNCTION) {
850        zend_type_error("Return value of %s%s%s() must %s%s, %s%s returned in %s on line %d",
851            fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind,
852            zf->op_array.filename->val, EG(current_execute_data)->opline->lineno);
853    } else {
854        zend_type_error("Return value of %s%s%s() must %s%s, %s%s returned",
855            fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
856    }
857}
858
859ZEND_API void zend_verify_internal_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
860{
861    const char *fname = zf->common.function_name->val;
862    const char *fsep;
863    const char *fclass;
864
865    if (zf->common.scope) {
866        fsep =  "::";
867        fclass = zf->common.scope->name->val;
868    } else {
869        fsep =  "";
870        fclass = "";
871    }
872
873    zend_error_noreturn(E_CORE_ERROR, "Return value of %s%s%s() must %s%s, %s%s returned",
874        fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
875}
876
877#if ZEND_DEBUG
878static int zend_verify_internal_return_type(zend_function *zf, zval *ret)
879{
880    zend_arg_info *ret_info = zf->common.arg_info - 1;
881    char *need_msg, *class_name;
882    zend_class_entry *ce;
883
884
885    if (ret_info->type_hint) {
886        if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
887            if (ret_info->class_name) {
888                need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
889                if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
890                    zend_verify_internal_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
891                    return 0;
892                }
893            }
894        } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
895            if (ret_info->class_name) {
896                need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
897                zend_verify_internal_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
898            } else if (ret_info->type_hint == IS_CALLABLE) {
899                if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
900                    zend_verify_internal_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
901                    return 0;
902                }
903            } else if (ret_info->type_hint == _IS_BOOL &&
904                       EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
905                /* pass */
906            } else {
907                /* Use strict check to verify return value of internal function */
908                zend_verify_internal_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
909                return 0;
910            }
911        }
912    }
913    return 1;
914}
915#endif
916
917static void zend_verify_return_type(zend_function *zf, zval *ret)
918{
919    zend_arg_info *ret_info = zf->common.arg_info - 1;
920    char *need_msg, *class_name;
921    zend_class_entry *ce;
922
923    if (ret_info->type_hint) {
924        if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
925            if (ret_info->class_name) {
926                need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
927                if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
928                    zend_verify_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
929                }
930            }
931        } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
932            if (ret_info->class_name) {
933                need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
934                zend_verify_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
935            } else if (ret_info->type_hint == IS_CALLABLE) {
936                if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL)) {
937                    zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
938                }
939            } else if (ret_info->type_hint == _IS_BOOL &&
940                       EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
941                /* pass */
942            } else if (UNEXPECTED(!zend_verify_scalar_type_hint(ret_info->type_hint, ret, ZEND_RET_USES_STRICT_TYPES()))) {
943                zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
944            }
945        }
946    }
947}
948
949static inline int zend_verify_missing_return_type(zend_function *zf)
950{
951    zend_arg_info *ret_info = zf->common.arg_info - 1;
952    char *need_msg;
953    zend_class_entry *ce;
954
955    if (ret_info->type_hint) {
956        if (ret_info->class_name) {
957            char *class_name;
958
959            need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
960            zend_verify_return_error(zf, need_msg, class_name, "none", "");
961            return 0;
962        } else if (ret_info->type_hint == IS_CALLABLE) {
963            zend_verify_return_error(zf, "be callable", "", "none", "");
964        } else {
965            zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), "none", "");
966        }
967        return 0;
968    }
969    return 1;
970}
971
972static zend_always_inline void zend_assign_to_object(zval *retval, zval *object, uint32_t object_op_type, zval *property_name, uint32_t property_op_type, int value_type, znode_op value_op, const zend_execute_data *execute_data, void **cache_slot)
973{
974    zend_free_op free_value;
975    zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R);
976    zval tmp;
977
978    if (object_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
979        do {
980            if (object_op_type == IS_VAR && UNEXPECTED(object == &EG(error_zval))) {
981                if (retval) {
982                    ZVAL_NULL(retval);
983                }
984                FREE_OP(free_value);
985                return;
986            }
987            if (Z_ISREF_P(object)) {
988                object = Z_REFVAL_P(object);
989                if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
990                    break;
991                }
992            }
993            if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE ||
994                (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
995                zend_object *obj;
996
997                zval_ptr_dtor(object);
998                object_init(object);
999                Z_ADDREF_P(object);
1000                obj = Z_OBJ_P(object);
1001                zend_error(E_WARNING, "Creating default object from empty value");
1002                if (GC_REFCOUNT(obj) == 1) {
1003                    /* the enclosing container was deleted, obj is unreferenced */
1004                    if (retval) {
1005                        ZVAL_NULL(retval);
1006                    }
1007                    FREE_OP(free_value);
1008                    OBJ_RELEASE(obj);
1009                    return;
1010                }
1011                Z_DELREF_P(object);
1012            } else {
1013                zend_error(E_WARNING, "Attempt to assign property of non-object");
1014                if (retval) {
1015                    ZVAL_NULL(retval);
1016                }
1017                FREE_OP(free_value);
1018                return;
1019            }
1020        } while (0);
1021    }
1022
1023    if (property_op_type == IS_CONST &&
1024        EXPECTED(Z_OBJCE_P(object) == CACHED_PTR_EX(cache_slot))) {
1025        uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
1026        zend_object *zobj = Z_OBJ_P(object);
1027        zval *property;
1028
1029        if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
1030            property = OBJ_PROP(zobj, prop_offset);
1031            if (Z_TYPE_P(property) != IS_UNDEF) {
1032fast_assign:
1033                value = zend_assign_to_variable(property, value, value_type);
1034                if (retval && EXPECTED(!EG(exception))) {
1035                    ZVAL_COPY(retval, value);
1036                }
1037                return;
1038            }
1039        } else {
1040            if (EXPECTED(zobj->properties != NULL)) {
1041                property = zend_hash_find(zobj->properties, Z_STR_P(property_name));
1042                if (property) {
1043                    goto fast_assign;
1044                }
1045            }
1046
1047            if (!zobj->ce->__set) {
1048
1049                if (EXPECTED(zobj->properties == NULL)) {
1050                    rebuild_object_properties(zobj);
1051                }
1052                /* separate our value if necessary */
1053                if (value_type == IS_CONST) {
1054                    if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
1055                        ZVAL_COPY_VALUE(&tmp, value);
1056                        zval_copy_ctor_func(&tmp);
1057                        value = &tmp;
1058                    }
1059                } else if (value_type != IS_TMP_VAR) {
1060                    if (Z_ISREF_P(value)) {
1061                        if (value_type == IS_VAR) {
1062                            zend_reference *ref = Z_REF_P(value);
1063                            if (--(GC_REFCOUNT(ref)) == 0) {
1064                                ZVAL_COPY_VALUE(&tmp, Z_REFVAL_P(value));
1065                                efree_size(ref, sizeof(zend_reference));
1066                                value = &tmp;
1067                            } else {
1068                                value = Z_REFVAL_P(value);
1069                                if (Z_REFCOUNTED_P(value)) {
1070                                    Z_ADDREF_P(value);
1071                                }
1072                            }
1073                        } else {
1074                            value = Z_REFVAL_P(value);
1075                            if (Z_REFCOUNTED_P(value)) {
1076                                Z_ADDREF_P(value);
1077                            }
1078                        }
1079                    } else if (value_type == IS_CV && Z_REFCOUNTED_P(value)) {
1080                        Z_ADDREF_P(value);
1081                    }
1082                }
1083                zend_hash_add_new(zobj->properties, Z_STR_P(property_name), value);
1084                if (retval) {
1085                    ZVAL_COPY(retval, value);
1086                }
1087                return;
1088            }
1089        }
1090    }
1091
1092    if (!Z_OBJ_HT_P(object)->write_property) {
1093        zend_error(E_WARNING, "Attempt to assign property of non-object");
1094        if (retval) {
1095            ZVAL_NULL(retval);
1096        }
1097        FREE_OP(free_value);
1098        return;
1099    }
1100
1101    /* separate our value if necessary */
1102    if (value_type == IS_CONST) {
1103        if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
1104            ZVAL_COPY_VALUE(&tmp, value);
1105            zval_copy_ctor_func(&tmp);
1106            value = &tmp;
1107        }
1108    } else if (value_type != IS_TMP_VAR) {
1109        ZVAL_DEREF(value);
1110    }
1111
1112    Z_OBJ_HT_P(object)->write_property(object, property_name, value, cache_slot);
1113
1114    if (retval && EXPECTED(!EG(exception))) {
1115        ZVAL_COPY(retval, value);
1116    }
1117    if (value_type == IS_CONST) {
1118        zval_ptr_dtor_nogc(value);
1119    } else {
1120        FREE_OP(free_value);
1121    }
1122}
1123
1124static zend_never_inline void zend_assign_to_object_dim(zval *retval, zval *object, zval *property_name, int value_type, znode_op value_op, const zend_execute_data *execute_data)
1125{
1126    zend_free_op free_value;
1127    zval *value = get_zval_ptr_deref(value_type, value_op, execute_data, &free_value, BP_VAR_R);
1128    zval tmp;
1129
1130    /* Note:  property_name in this case is really the array index! */
1131    if (!Z_OBJ_HT_P(object)->write_dimension) {
1132        zend_error(E_EXCEPTION | E_ERROR, "Cannot use object as array");
1133        FREE_OP(free_value);
1134        return;
1135    }
1136
1137    /* separate our value if necessary */
1138    if (value_type == IS_CONST) {
1139        if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
1140            ZVAL_COPY_VALUE(&tmp, value);
1141            zval_copy_ctor_func(&tmp);
1142            value = &tmp;
1143        }
1144    }
1145
1146    Z_OBJ_HT_P(object)->write_dimension(object, property_name, value);
1147
1148    if (retval && EXPECTED(!EG(exception))) {
1149        ZVAL_COPY(retval, value);
1150    }
1151    if (value_type == IS_CONST) {
1152        zval_ptr_dtor_nogc(value);
1153    } else {
1154        FREE_OP(free_value);
1155    }
1156}
1157
1158static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, binary_op_type binary_op)
1159{
1160    zval *z;
1161    zval rv, res;
1162
1163    if (Z_OBJ_HT_P(object)->read_dimension &&
1164        (z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv)) != NULL) {
1165
1166        if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
1167            zval rv2;
1168            zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
1169
1170            if (z == &rv) {
1171                zval_ptr_dtor(&rv);
1172            }
1173            ZVAL_COPY_VALUE(z, value);
1174        }
1175        binary_op(&res, Z_ISREF_P(z) ? Z_REFVAL_P(z) : z, value);
1176        Z_OBJ_HT_P(object)->write_dimension(object, property, &res);
1177        if (z == &rv) {
1178            zval_ptr_dtor(&rv);
1179        }
1180        if (retval) {
1181            ZVAL_COPY(retval, &res);
1182        }
1183        zval_ptr_dtor(&res);
1184    } else {
1185        zend_error(E_WARNING, "Attempt to assign property of non-object");
1186        if (retval) {
1187            ZVAL_NULL(retval);
1188        }
1189    }
1190}
1191
1192static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, zval *result)
1193{
1194    zend_string *old_str;
1195
1196    if (offset < 0) {
1197        zend_error(E_WARNING, "Illegal string offset:  " ZEND_LONG_FMT, offset);
1198        zend_string_release(Z_STR_P(str));
1199        if (result) {
1200            ZVAL_NULL(result);
1201        }
1202        return;
1203    }
1204
1205    old_str = Z_STR_P(str);
1206    if ((size_t)offset >= Z_STRLEN_P(str)) {
1207        zend_long old_len = Z_STRLEN_P(str);
1208        Z_STR_P(str) = zend_string_extend(Z_STR_P(str), offset + 1, 0);
1209        Z_TYPE_INFO_P(str) = IS_STRING_EX;
1210        memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
1211        Z_STRVAL_P(str)[offset+1] = 0;
1212    } else if (!Z_REFCOUNTED_P(str)) {
1213        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
1214        Z_TYPE_INFO_P(str) = IS_STRING_EX;
1215    }
1216
1217    if (Z_TYPE_P(value) != IS_STRING) {
1218        zend_string *tmp = zval_get_string(value);
1219
1220        Z_STRVAL_P(str)[offset] = tmp->val[0];
1221        zend_string_release(tmp);
1222    } else {
1223        Z_STRVAL_P(str)[offset] = Z_STRVAL_P(value)[0];
1224    }
1225    /*
1226     * the value of an assignment to a string offset is undefined
1227    T(result->u.var).var = &T->str_offset.str;
1228    */
1229
1230    zend_string_release(old_str);
1231    if (result) {
1232        zend_uchar c = (zend_uchar)Z_STRVAL_P(str)[offset];
1233
1234        if (CG(one_char_string)[c]) {
1235            ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
1236        } else {
1237            ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(str) + offset, 1, 0));
1238        }
1239    }
1240}
1241
1242/* Utility Functions for Extensions */
1243static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array)
1244{
1245    if (extension->statement_handler) {
1246        extension->statement_handler(op_array);
1247    }
1248}
1249
1250
1251static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array)
1252{
1253    if (extension->fcall_begin_handler) {
1254        extension->fcall_begin_handler(op_array);
1255    }
1256}
1257
1258
1259static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array)
1260{
1261    if (extension->fcall_end_handler) {
1262        extension->fcall_end_handler(op_array);
1263    }
1264}
1265
1266
1267static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_data *execute_data, int fetch_type)
1268{
1269    HashTable *ht;
1270
1271    if (EXPECTED(fetch_type == ZEND_FETCH_GLOBAL_LOCK) ||
1272        EXPECTED(fetch_type == ZEND_FETCH_GLOBAL)) {
1273        ht = &EG(symbol_table);
1274    } else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
1275        ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
1276        ht = EX(func)->op_array.static_variables;
1277        if (GC_REFCOUNT(ht) > 1) {
1278            if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
1279                GC_REFCOUNT(ht)--;
1280            }
1281            EX(func)->op_array.static_variables = ht = zend_array_dup(ht);
1282        }
1283    } else {
1284        ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
1285        if (!EX(symbol_table)) {
1286            zend_rebuild_symbol_table();
1287        }
1288        ht = EX(symbol_table);
1289    }
1290    return ht;
1291}
1292
1293static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type)
1294{
1295    zval *retval;
1296    zend_string *offset_key;
1297    zend_ulong hval;
1298
1299try_again:
1300    if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
1301        hval = Z_LVAL_P(dim);
1302num_index:
1303        retval = zend_hash_index_find(ht, hval);
1304        if (retval == NULL) {
1305            switch (type) {
1306                case BP_VAR_R:
1307                    zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, hval);
1308                    /* break missing intentionally */
1309                case BP_VAR_UNSET:
1310                case BP_VAR_IS:
1311                    retval = &EG(uninitialized_zval);
1312                    break;
1313                case BP_VAR_RW:
1314                    zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, hval);
1315                    /* break missing intentionally */
1316                case BP_VAR_W:
1317                    retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
1318                    break;
1319            }
1320        }
1321    } else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
1322        offset_key = Z_STR_P(dim);
1323        if (dim_type != IS_CONST) {
1324            if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
1325                goto num_index;
1326            }
1327        }
1328str_index:
1329        retval = zend_hash_find(ht, offset_key);
1330        if (retval) {
1331            /* support for $GLOBALS[...] */
1332            if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
1333                retval = Z_INDIRECT_P(retval);
1334                if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
1335                    switch (type) {
1336                        case BP_VAR_R:
1337                            zend_error(E_NOTICE, "Undefined index: %s", offset_key->val);
1338                            /* break missing intentionally */
1339                        case BP_VAR_UNSET:
1340                        case BP_VAR_IS:
1341                            retval = &EG(uninitialized_zval);
1342                            break;
1343                        case BP_VAR_RW:
1344                            zend_error(E_NOTICE,"Undefined index: %s", offset_key->val);
1345                            /* break missing intentionally */
1346                        case BP_VAR_W:
1347                            ZVAL_NULL(retval);
1348                            break;
1349                    }
1350                }
1351            }
1352        } else {
1353            switch (type) {
1354                case BP_VAR_R:
1355                    zend_error(E_NOTICE, "Undefined index: %s", offset_key->val);
1356                    /* break missing intentionally */
1357                case BP_VAR_UNSET:
1358                case BP_VAR_IS:
1359                    retval = &EG(uninitialized_zval);
1360                    break;
1361                case BP_VAR_RW:
1362                    zend_error(E_NOTICE,"Undefined index: %s", offset_key->val);
1363                    /* break missing intentionally */
1364                case BP_VAR_W:
1365                    retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
1366                    break;
1367            }
1368        }
1369    } else {
1370        switch (Z_TYPE_P(dim)) {
1371            case IS_NULL:
1372                offset_key = STR_EMPTY_ALLOC();
1373                goto str_index;
1374            case IS_DOUBLE:
1375                hval = zend_dval_to_lval(Z_DVAL_P(dim));
1376                goto num_index;
1377            case IS_RESOURCE:
1378                zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
1379                hval = Z_RES_HANDLE_P(dim);
1380                goto num_index;
1381            case IS_FALSE:
1382                hval = 0;
1383                goto num_index;
1384            case IS_TRUE:
1385                hval = 1;
1386                goto num_index;
1387            case IS_REFERENCE:
1388                dim = Z_REFVAL_P(dim);
1389                goto try_again;
1390            default:
1391                zend_error(E_WARNING, "Illegal offset type");
1392                retval = (type == BP_VAR_W || type == BP_VAR_RW) ?
1393                    &EG(error_zval) : &EG(uninitialized_zval);
1394        }
1395    }
1396    return retval;
1397}
1398
1399static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type)
1400{
1401    zend_long offset;
1402
1403try_again:
1404    if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1405        switch(Z_TYPE_P(dim)) {
1406            case IS_STRING:
1407                if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1408                    break;
1409                }
1410                if (type != BP_VAR_UNSET) {
1411                    zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1412                }
1413                break;
1414            case IS_DOUBLE:
1415            case IS_NULL:
1416            case IS_FALSE:
1417            case IS_TRUE:
1418                zend_error(E_NOTICE, "String offset cast occurred");
1419                break;
1420            case IS_REFERENCE:
1421                dim = Z_REFVAL_P(dim);
1422                goto try_again;
1423            default:
1424                zend_error(E_WARNING, "Illegal offset type");
1425                break;
1426        }
1427
1428        offset = zval_get_long(dim);
1429    } else {
1430        offset = Z_LVAL_P(dim);
1431    }
1432
1433    return offset;
1434}
1435
1436static zend_always_inline zend_long zend_fetch_string_offset(zval *container, zval *dim, int type)
1437{
1438    zend_long offset = zend_check_string_offset(dim, type);
1439
1440    if (Z_REFCOUNTED_P(container)) {
1441        if (Z_REFCOUNT_P(container) > 1) {
1442            Z_DELREF_P(container);
1443            zval_copy_ctor_func(container);
1444        }
1445        Z_ADDREF_P(container);
1446    }
1447    return offset;
1448}
1449
1450static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type)
1451{
1452    zval *retval;
1453
1454try_again:
1455    if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1456        SEPARATE_ARRAY(container);
1457fetch_from_array:
1458        if (dim == NULL) {
1459            retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
1460            if (UNEXPECTED(retval == NULL)) {
1461                zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
1462                retval = &EG(error_zval);
1463            }
1464        } else {
1465            retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
1466        }
1467        ZVAL_INDIRECT(result, retval);
1468    } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1469        if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) {
1470            zval_ptr_dtor_nogc(container);
1471convert_to_array:
1472            ZVAL_NEW_ARR(container);
1473            zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
1474            goto fetch_from_array;
1475        }
1476
1477        if (dim == NULL) {
1478            zend_error(E_EXCEPTION | E_ERROR, "[] operator not supported for strings");
1479        } else {
1480            zend_check_string_offset(dim, type);
1481        }
1482
1483        ZVAL_INDIRECT(result, NULL); /* wrong string offset */
1484    } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1485        if (!Z_OBJ_HT_P(container)->read_dimension) {
1486            zend_error(E_EXCEPTION | E_ERROR, "Cannot use object as array");
1487            retval = &EG(error_zval);
1488        } else {
1489            retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
1490
1491            if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
1492                zend_class_entry *ce = Z_OBJCE_P(container);
1493
1494                ZVAL_NULL(result);
1495                zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name->val);
1496            } else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) {
1497                if (!Z_ISREF_P(retval)) {
1498                    if (Z_REFCOUNTED_P(retval) &&
1499                        Z_REFCOUNT_P(retval) > 1) {
1500                        if (Z_TYPE_P(retval) != IS_OBJECT) {
1501                            Z_DELREF_P(retval);
1502                            ZVAL_DUP(result, retval);
1503                            retval = result;
1504                        } else {
1505                            ZVAL_COPY(result, retval);
1506                            retval = result;
1507                        }
1508                    }
1509                    if (Z_TYPE_P(retval) != IS_OBJECT) {
1510                        zend_class_entry *ce = Z_OBJCE_P(container);
1511                        zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name->val);
1512                    }
1513                }
1514                if (result != retval) {
1515                    ZVAL_INDIRECT(result, retval);
1516                }
1517            } else {
1518                ZVAL_INDIRECT(result, &EG(error_zval));
1519            }
1520        }
1521    } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
1522        if (UNEXPECTED(container == &EG(error_zval))) {
1523            ZVAL_INDIRECT(result, &EG(error_zval));
1524        } else if (type != BP_VAR_UNSET) {
1525            goto convert_to_array;
1526        } else {
1527            /* for read-mode only */
1528            ZVAL_NULL(result);
1529        }
1530    } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
1531        container = Z_REFVAL_P(container);
1532        goto try_again;
1533    } else {
1534        if (type == BP_VAR_UNSET) {
1535            zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1536            ZVAL_NULL(result);
1537        } else {
1538            zend_error(E_WARNING, "Cannot use a scalar value as an array");
1539            ZVAL_INDIRECT(result, &EG(error_zval));
1540        }
1541    }
1542}
1543
1544static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type)
1545{
1546    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W);
1547}
1548
1549static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type)
1550{
1551    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW);
1552}
1553
1554static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type)
1555{
1556    zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET);
1557}
1558
1559static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type)
1560{
1561    zval *retval;
1562
1563try_again:
1564    if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1565        retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
1566        ZVAL_COPY(result, retval);
1567    } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1568        zend_long offset;
1569
1570try_string_offset:
1571        if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1572            switch(Z_TYPE_P(dim)) {
1573                /* case IS_LONG: */
1574                case IS_STRING:
1575                    if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1576                        break;
1577                    }
1578                    if (type != BP_VAR_IS) {
1579                        zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1580                    }
1581                    break;
1582                case IS_DOUBLE:
1583                case IS_NULL:
1584                case IS_FALSE:
1585                case IS_TRUE:
1586                    if (type != BP_VAR_IS) {
1587                        zend_error(E_NOTICE, "String offset cast occurred");
1588                    }
1589                    break;
1590                case IS_REFERENCE:
1591                    dim = Z_REFVAL_P(dim);
1592                    goto try_string_offset;
1593                default:
1594                    zend_error(E_WARNING, "Illegal offset type");
1595                    break;
1596            }
1597
1598            offset = zval_get_long(dim);
1599        } else {
1600            offset = Z_LVAL_P(dim);
1601        }
1602
1603        if (UNEXPECTED(offset < 0) || UNEXPECTED(Z_STRLEN_P(container) <= (size_t)offset)) {
1604            if (type != BP_VAR_IS) {
1605                zend_error(E_NOTICE, "Uninitialized string offset: %pd", offset);
1606            }
1607            ZVAL_EMPTY_STRING(result);
1608        } else {
1609            zend_uchar c = (zend_uchar)Z_STRVAL_P(container)[offset];
1610
1611            if (CG(one_char_string)[c]) {
1612                ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
1613            } else {
1614                ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + offset, 1, 0));
1615            }
1616        }
1617    } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1618        if (!Z_OBJ_HT_P(container)->read_dimension) {
1619            zend_error(E_EXCEPTION | E_ERROR, "Cannot use object as array");
1620            ZVAL_NULL(result);
1621        } else {
1622            retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
1623
1624            ZEND_ASSERT(result != NULL);
1625            if (retval) {
1626                if (result != retval) {
1627                    ZVAL_COPY(result, retval);
1628                }
1629            } else {
1630                ZVAL_NULL(result);
1631            }
1632        }
1633    } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
1634        container = Z_REFVAL_P(container);
1635        goto try_again;
1636    } else {
1637        ZVAL_NULL(result);
1638    }
1639}
1640
1641static zend_never_inline void zend_fetch_dimension_address_read_R(zval *result, zval *container, zval *dim, int dim_type)
1642{
1643    zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R);
1644}
1645
1646static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zval *container, zval *dim, int dim_type)
1647{
1648    zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS);
1649}
1650
1651ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim)
1652{
1653    zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR);
1654}
1655
1656static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type)
1657{
1658    if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) {
1659        do {
1660            if (container_op_type == IS_VAR && UNEXPECTED(container == &EG(error_zval))) {
1661                ZVAL_INDIRECT(result, &EG(error_zval));
1662                return;
1663            }
1664
1665            if (Z_ISREF_P(container)) {
1666                container = Z_REFVAL_P(container);
1667                if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1668                    break;
1669                }
1670            }
1671
1672            /* this should modify object only if it's empty */
1673            if (type != BP_VAR_UNSET &&
1674                EXPECTED(Z_TYPE_P(container) <= IS_FALSE ||
1675                  (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0))) {
1676                zval_ptr_dtor_nogc(container);
1677                object_init(container);
1678            } else {
1679                zend_error(E_WARNING, "Attempt to modify property of non-object");
1680                ZVAL_INDIRECT(result, &EG(error_zval));
1681                return;
1682            }
1683        } while (0);
1684    }
1685    if (prop_op_type == IS_CONST &&
1686        EXPECTED(Z_OBJCE_P(container) == CACHED_PTR_EX(cache_slot))) {
1687        uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
1688        zend_object *zobj = Z_OBJ_P(container);
1689        zval *retval;
1690
1691        if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
1692            retval = OBJ_PROP(zobj, prop_offset);
1693            if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
1694                ZVAL_INDIRECT(result, retval);
1695                return;
1696            }
1697        } else if (EXPECTED(zobj->properties != NULL)) {
1698            retval = zend_hash_find(zobj->properties, Z_STR_P(prop_ptr));
1699            if (EXPECTED(retval)) {
1700                ZVAL_INDIRECT(result, retval);
1701                return;
1702            }
1703        }
1704    }
1705    if (EXPECTED(Z_OBJ_HT_P(container)->get_property_ptr_ptr)) {
1706        zval *ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, type, cache_slot);
1707        if (NULL == ptr) {
1708            if (Z_OBJ_HT_P(container)->read_property &&
1709                (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result)) != NULL) {
1710                if (ptr != result) {
1711                    ZVAL_INDIRECT(result, ptr);
1712                }
1713            } else {
1714                zend_error(E_EXCEPTION | E_ERROR, "Cannot access undefined property for object with overloaded property access");
1715                ZVAL_INDIRECT(result, &EG(error_zval));
1716            }
1717        } else {
1718            ZVAL_INDIRECT(result, ptr);
1719        }
1720    } else if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) {
1721        zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result);
1722        if (ptr != result) {
1723            ZVAL_INDIRECT(result, ptr);
1724        }
1725    } else {
1726        zend_error(E_WARNING, "This object doesn't support property references");
1727        ZVAL_INDIRECT(result, &EG(error_zval));
1728    }
1729}
1730
1731static 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)
1732{
1733    zend_brk_cont_element *jmp_to;
1734
1735    do {
1736        ZEND_ASSERT(array_offset != -1);
1737        jmp_to = &op_array->brk_cont_array[array_offset];
1738        if (nest_levels>1) {
1739            zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
1740
1741            if (brk_opline->opcode == ZEND_FREE) {
1742                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
1743                    zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
1744                }
1745            } else if (brk_opline->opcode == ZEND_FE_FREE) {
1746                if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
1747                    zval *var = EX_VAR(brk_opline->op1.var);
1748                    if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
1749                        zend_hash_iterator_del(Z_FE_ITER_P(var));
1750                    }
1751                    zval_ptr_dtor_nogc(var);
1752                }
1753            }
1754        }
1755        array_offset = jmp_to->parent;
1756    } while (--nest_levels > 0);
1757    return jmp_to;
1758}
1759
1760#if ZEND_INTENSIVE_DEBUGGING
1761
1762#define CHECK_SYMBOL_TABLES()                                                   \
1763    zend_hash_apply(&EG(symbol_table), zend_check_symbol);          \
1764    if (&EG(symbol_table)!=EX(symbol_table)) {                          \
1765        zend_hash_apply(EX(symbol_table), zend_check_symbol);   \
1766    }
1767
1768static int zend_check_symbol(zval *pz)
1769{
1770    if (Z_TYPE_P(pz) == IS_INDIRECT) {
1771        pz = Z_INDIRECT_P(pz);
1772    }
1773    if (Z_TYPE_P(pz) > 10) {
1774        fprintf(stderr, "Warning!  %x has invalid type!\n", *pz);
1775/* See http://support.microsoft.com/kb/190351 */
1776#ifdef PHP_WIN32
1777        fflush(stderr);
1778#endif
1779    } else if (Z_TYPE_P(pz) == IS_ARRAY) {
1780        zend_hash_apply(Z_ARRVAL_P(pz), zend_check_symbol);
1781    } else if (Z_TYPE_P(pz) == IS_OBJECT) {
1782        /* OBJ-TBI - doesn't support new object model! */
1783        zend_hash_apply(Z_OBJPROP_P(pz), zend_check_symbol);
1784    }
1785
1786    return 0;
1787}
1788
1789
1790#else
1791#define CHECK_SYMBOL_TABLES()
1792#endif
1793
1794ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value)
1795{
1796    execute_data->func->internal_function.handler(execute_data, return_value);
1797}
1798
1799ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{ */
1800{
1801    if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
1802        zend_array_destroy(symbol_table);
1803    } else {
1804        /* clean before putting into the cache, since clean
1805           could call dtors, which could use cached hash */
1806        zend_symtable_clean(symbol_table);
1807        *(++EG(symtable_cache_ptr)) = symbol_table;
1808    }
1809}
1810/* }}} */
1811
1812static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
1813{
1814    zval *cv = EX_VAR_NUM(0);
1815    zval *end = cv + EX(func)->op_array.last_var;
1816    while (EXPECTED(cv != end)) {
1817        if (Z_REFCOUNTED_P(cv)) {
1818            if (!Z_DELREF_P(cv)) {
1819                zend_refcounted *r = Z_COUNTED_P(cv);
1820                ZVAL_NULL(cv);
1821                zval_dtor_func_for_ptr(r);
1822            } else {
1823                GC_ZVAL_CHECK_POSSIBLE_ROOT(cv);
1824            }
1825        }
1826        cv++;
1827    }
1828}
1829/* }}} */
1830
1831void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
1832{
1833    i_free_compiled_variables(execute_data);
1834}
1835/* }}} */
1836
1837#ifdef ZEND_WIN32
1838# define ZEND_VM_INTERRUPT_CHECK() do { \
1839        if (EG(timed_out)) { \
1840            zend_timeout(0); \
1841        } \
1842    } while (0)
1843#else
1844# define ZEND_VM_INTERRUPT_CHECK() do { \
1845    } while (0)
1846#endif
1847
1848/*
1849 * Stack Frame Layout (the whole stack frame is allocated at once)
1850 * ==================
1851 *
1852 *                             +========================================+
1853 * EG(current_execute_data) -> | zend_execute_data                      |
1854 *                             +----------------------------------------+
1855 *     EX_CV_NUM(0) ---------> | VAR[0] = ARG[1]                        |
1856 *                             | ...                                    |
1857 *                             | VAR[op_array->num_args-1] = ARG[N]     |
1858 *                             | ...                                    |
1859 *                             | VAR[op_array->last_var-1]              |
1860 *                             | VAR[op_array->last_var] = TMP[0]       |
1861 *                             | ...                                    |
1862 *                             | VAR[op_array->last_var+op_array->T-1]  |
1863 *                             | ARG[N+1] (extra_args)                  |
1864 *                             | ...                                    |
1865 *                             +----------------------------------------+
1866 */
1867
1868static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */
1869{
1870    uint32_t first_extra_arg, num_args;
1871    ZEND_ASSERT(EX(func) == (zend_function*)op_array);
1872
1873    EX(opline) = op_array->opcodes;
1874    EX(call) = NULL;
1875    EX(return_value) = return_value;
1876
1877    /* Handle arguments */
1878    first_extra_arg = op_array->num_args;
1879    num_args = EX_NUM_ARGS();
1880    if (UNEXPECTED(num_args > first_extra_arg)) {
1881        zval *end, *src, *dst;
1882        uint32_t type_flags = 0;
1883
1884        if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
1885            /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
1886            EX(opline) += first_extra_arg;
1887        }
1888
1889        /* move extra args into separate array after all CV and TMP vars */
1890        end = EX_VAR_NUM(first_extra_arg - 1);
1891        src = end + (num_args - first_extra_arg);
1892        dst = src + (op_array->last_var + op_array->T - first_extra_arg);
1893        if (EXPECTED(src != dst)) {
1894            do {
1895                type_flags |= Z_TYPE_INFO_P(src);
1896                ZVAL_COPY_VALUE(dst, src);
1897                ZVAL_UNDEF(src);
1898                src--;
1899                dst--;
1900            } while (src != end);
1901        } else {
1902            do {
1903                type_flags |= Z_TYPE_INFO_P(src);
1904                src--;
1905            } while (src != end);
1906        }
1907        ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
1908    } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
1909        /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
1910        EX(opline) += num_args;
1911    }
1912
1913    /* Initialize CV variables (skip arguments) */
1914    if (EXPECTED((int)num_args < op_array->last_var)) {
1915        zval *var = EX_VAR_NUM(num_args);
1916        zval *end = EX_VAR_NUM(op_array->last_var);
1917
1918        do {
1919            ZVAL_UNDEF(var);
1920            var++;
1921        } while (var != end);
1922    }
1923
1924    if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
1925        ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
1926        GC_REFCOUNT(Z_OBJ(EX(This)))++;
1927    }
1928
1929    if (UNEXPECTED(!op_array->run_time_cache)) {
1930        op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
1931        memset(op_array->run_time_cache, 0, op_array->cache_size);
1932    }
1933    EX_LOAD_RUN_TIME_CACHE(op_array);
1934    EX_LOAD_LITERALS(op_array);
1935
1936    EG(current_execute_data) = execute_data;
1937    ZEND_VM_INTERRUPT_CHECK();
1938}
1939/* }}} */
1940
1941static zend_always_inline void i_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
1942{
1943    ZEND_ASSERT(EX(func) == (zend_function*)op_array);
1944
1945    EX(opline) = op_array->opcodes;
1946    EX(call) = NULL;
1947    EX(return_value) = return_value;
1948
1949    zend_attach_symbol_table(execute_data);
1950
1951    if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
1952        ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
1953        GC_REFCOUNT(Z_OBJ(EX(This)))++;
1954    }
1955
1956    if (!op_array->run_time_cache) {
1957        op_array->run_time_cache = emalloc(op_array->cache_size);
1958        memset(op_array->run_time_cache, 0, op_array->cache_size);
1959    }
1960    EX_LOAD_RUN_TIME_CACHE(op_array);
1961    EX_LOAD_LITERALS(op_array);
1962
1963    EG(current_execute_data) = execute_data;
1964    ZEND_VM_INTERRUPT_CHECK();
1965}
1966/* }}} */
1967
1968static zend_always_inline void i_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
1969{
1970    ZEND_ASSERT(EX(func) == (zend_function*)op_array);
1971
1972    EX(opline) = op_array->opcodes;
1973    EX(call) = NULL;
1974    EX(return_value) = return_value;
1975
1976    if (UNEXPECTED(EX(symbol_table) != NULL)) {
1977        zend_attach_symbol_table(execute_data);
1978    } else {
1979        uint32_t first_extra_arg, num_args;
1980
1981        /* Handle arguments */
1982        first_extra_arg = op_array->num_args;
1983        num_args = EX_NUM_ARGS();
1984        if (UNEXPECTED(num_args > first_extra_arg)) {
1985            zval *end, *src, *dst;
1986            uint32_t type_flags = 0;
1987
1988            if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
1989                /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
1990                EX(opline) += first_extra_arg;
1991            }
1992
1993            /* move extra args into separate array after all CV and TMP vars */
1994            end = EX_VAR_NUM(first_extra_arg - 1);
1995            src = end + (num_args - first_extra_arg);
1996            dst = src + (op_array->last_var + op_array->T - first_extra_arg);
1997            if (EXPECTED(src != dst)) {
1998                do {
1999                    type_flags |= Z_TYPE_INFO_P(src);
2000                    ZVAL_COPY_VALUE(dst, src);
2001                    ZVAL_UNDEF(src);
2002                    src--;
2003                    dst--;
2004                } while (src != end);
2005            } else {
2006                do {
2007                    type_flags |= Z_TYPE_INFO_P(src);
2008                    src--;
2009                } while (src != end);
2010            }
2011            ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
2012        } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
2013            /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
2014            EX(opline) += num_args;
2015        }
2016
2017        /* Initialize CV variables (skip arguments) */
2018        if (EXPECTED((int)num_args < op_array->last_var)) {
2019            zval *var = EX_VAR_NUM(num_args);
2020            zval *end = EX_VAR_NUM(op_array->last_var);
2021
2022            do {
2023                ZVAL_UNDEF(var);
2024                var++;
2025            } while (var != end);
2026        }
2027    }
2028
2029    if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
2030        ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
2031        GC_REFCOUNT(Z_OBJ(EX(This)))++;
2032    }
2033
2034    if (!op_array->run_time_cache) {
2035        if (op_array->function_name) {
2036            op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
2037        } else {
2038            op_array->run_time_cache = emalloc(op_array->cache_size);
2039        }
2040        memset(op_array->run_time_cache, 0, op_array->cache_size);
2041    }
2042    EX_LOAD_RUN_TIME_CACHE(op_array);
2043    EX_LOAD_LITERALS(op_array);
2044
2045    EG(current_execute_data) = execute_data;
2046    ZEND_VM_INTERRUPT_CHECK();
2047}
2048/* }}} */
2049
2050ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value) /* {{{ */
2051{
2052    /*
2053     * Normally the execute_data is allocated on the VM stack (because it does
2054     * not actually do any allocation and thus is faster). For generators
2055     * though this behavior would be suboptimal, because the (rather large)
2056     * structure would have to be copied back and forth every time execution is
2057     * suspended or resumed. That's why for generators the execution context
2058     * is allocated using a separate VM stack, thus allowing to save and
2059     * restore it simply by replacing a pointer.
2060     */
2061    zend_execute_data *execute_data;
2062    uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
2063    size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval);
2064
2065    EG(vm_stack) = zend_vm_stack_new_page(
2066        EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE(1)) ?
2067            ZEND_VM_STACK_PAGE_SIZE(1) :
2068            ZEND_VM_STACK_PAGE_ALIGNED_SIZE(1, stack_size),
2069        NULL);
2070    EG(vm_stack_top) = EG(vm_stack)->top;
2071    EG(vm_stack_end) = EG(vm_stack)->end;
2072
2073    execute_data = zend_vm_stack_push_call_frame(
2074        ZEND_CALL_TOP_FUNCTION | (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE),
2075        (zend_function*)op_array,
2076        num_args,
2077        call->called_scope,
2078        Z_OBJ(call->This));
2079    EX(prev_execute_data) = NULL;
2080    EX_NUM_ARGS() = num_args;
2081
2082    /* copy arguments */
2083    if (num_args > 0) {
2084        zval *arg_src = ZEND_CALL_ARG(call, 1);
2085        zval *arg_dst = ZEND_CALL_ARG(execute_data, 1);
2086        uint32_t i;
2087
2088        for (i = 0; i < num_args; i++) {
2089            ZVAL_COPY_VALUE(arg_dst + i, arg_src + i);
2090        }
2091    }
2092
2093    EX(symbol_table) = NULL;
2094
2095    i_init_func_execute_data(execute_data, op_array, return_value, 1);
2096
2097    return execute_data;
2098}
2099/* }}} */
2100
2101ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
2102{
2103    EX(prev_execute_data) = EG(current_execute_data);
2104    i_init_execute_data(execute_data, op_array, return_value);
2105}
2106/* }}} */
2107
2108static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(const zend_op *opline, zend_execute_data *call) /* {{{ */
2109{
2110    uint32_t arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK;
2111    return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num);
2112}
2113/* }}} */
2114
2115static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, uint32_t passed_args, uint32_t additional_args) /* {{{ */
2116{
2117    zend_execute_data *new_call;
2118    int used_stack = (EG(vm_stack_top) - (zval*)call) + additional_args;
2119
2120    /* copy call frame into new stack segment */
2121    new_call = zend_vm_stack_extend(used_stack * sizeof(zval));
2122    *new_call = *call;
2123    if (passed_args) {
2124        zval *src = ZEND_CALL_ARG(call, 1);
2125        zval *dst = ZEND_CALL_ARG(new_call, 1);
2126        do {
2127            ZVAL_COPY_VALUE(dst, src);
2128            passed_args--;
2129            src++;
2130            dst++;
2131        } while (passed_args);
2132    }
2133
2134    /* delete old call_frame from previous stack segment */
2135    EG(vm_stack)->prev->top = (zval*)call;
2136
2137    /* delete previous stack segment if it becames empty */
2138    if (UNEXPECTED(EG(vm_stack)->prev->top == ZEND_VM_STACK_ELEMETS(EG(vm_stack)->prev))) {
2139        zend_vm_stack r = EG(vm_stack)->prev;
2140
2141        EG(vm_stack)->prev = r->prev;
2142        efree(r);
2143    }
2144
2145    return new_call;
2146}
2147/* }}} */
2148
2149static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, uint32_t passed_args, uint32_t additional_args) /* {{{ */
2150{
2151    if (EXPECTED((uint32_t)(EG(vm_stack_end) - EG(vm_stack_top)) > additional_args)) {
2152        EG(vm_stack_top) += additional_args;
2153    } else {
2154        *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args);
2155    }
2156}
2157/* }}} */
2158
2159static zend_always_inline zend_generator *zend_get_running_generator(zend_execute_data *execute_data) /* {{{ */
2160{
2161    /* The generator object is stored in EX(return_value) */
2162    zend_generator *generator = (zend_generator *) EX(return_value);
2163    /* However control may currently be delegated to another generator.
2164     * That's the one we're interested in. */
2165    return generator;
2166}
2167/* }}} */
2168
2169#ifdef HAVE_GCC_GLOBAL_REGS
2170# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
2171#  define ZEND_VM_FP_GLOBAL_REG "%esi"
2172#  define ZEND_VM_IP_GLOBAL_REG "%edi"
2173# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
2174#  define ZEND_VM_FP_GLOBAL_REG "%r14"
2175#  define ZEND_VM_IP_GLOBAL_REG "%r15"
2176# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
2177#  define ZEND_VM_FP_GLOBAL_REG "r28"
2178#  define ZEND_VM_IP_GLOBAL_REG "r29"
2179# endif
2180#endif
2181
2182#define ZEND_VM_NEXT_OPCODE() \
2183    CHECK_SYMBOL_TABLES() \
2184    ZEND_VM_INC_OPCODE(); \
2185    ZEND_VM_CONTINUE()
2186
2187#define ZEND_VM_SET_NEXT_OPCODE(new_op) \
2188    CHECK_SYMBOL_TABLES() \
2189    OPLINE = new_op
2190
2191#define ZEND_VM_SET_OPCODE(new_op) \
2192    CHECK_SYMBOL_TABLES() \
2193    OPLINE = new_op; \
2194    ZEND_VM_INTERRUPT_CHECK()
2195
2196#define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
2197    ZEND_VM_SET_OPCODE(ZEND_OFFSET_TO_OPLINE(opline, offset))
2198
2199#define ZEND_VM_JMP(new_op) \
2200    if (EXPECTED(!EG(exception))) { \
2201        ZEND_VM_SET_OPCODE(new_op); \
2202    } else { \
2203        LOAD_OPLINE(); \
2204    } \
2205    ZEND_VM_CONTINUE()
2206
2207#define ZEND_VM_INC_OPCODE() \
2208    OPLINE++
2209
2210#ifdef __GNUC__
2211# define ZEND_VM_GUARD(name) __asm__("#" #name)
2212#else
2213# define ZEND_VM_GUARD(name)
2214#endif
2215
2216#define GET_OP1_UNDEF_CV(ptr, type) \
2217    _get_zval_cv_lookup_ ## type(ptr, opline->op1.var, execute_data)
2218#define GET_OP2_UNDEF_CV(ptr, type) \
2219    _get_zval_cv_lookup_ ## type(ptr, opline->op2.var, execute_data)
2220
2221#include "zend_vm_execute.h"
2222
2223ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
2224{
2225    if (opcode != ZEND_USER_OPCODE) {
2226        if (handler == NULL) {
2227            /* restore the original handler */
2228            zend_user_opcodes[opcode] = opcode;
2229        } else {
2230            zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
2231        }
2232        zend_user_opcode_handlers[opcode] = handler;
2233        return SUCCESS;
2234    }
2235    return FAILURE;
2236}
2237
2238ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
2239{
2240    return zend_user_opcode_handlers[opcode];
2241}
2242
2243ZEND_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) {
2244    return get_zval_ptr(op_type, *node, execute_data, should_free, type);
2245}
2246
2247/*
2248 * Local variables:
2249 * tab-width: 4
2250 * c-basic-offset: 4
2251 * indent-tabs-mode: t
2252 * End:
2253 */
2254