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