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