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