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