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