xref: /PHP-8.2/Zend/zend_execute.c (revision cd255007)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 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@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    |          Dmitry Stogov <dmitry@php.net>                              |
18    +----------------------------------------------------------------------+
19 */
20 
21 #define ZEND_INTENSIVE_DEBUGGING 0
22 
23 #include <stdio.h>
24 #include <signal.h>
25 
26 #include "zend.h"
27 #include "zend_compile.h"
28 #include "zend_execute.h"
29 #include "zend_API.h"
30 #include "zend_ptr_stack.h"
31 #include "zend_constants.h"
32 #include "zend_extensions.h"
33 #include "zend_ini.h"
34 #include "zend_exceptions.h"
35 #include "zend_interfaces.h"
36 #include "zend_closures.h"
37 #include "zend_generators.h"
38 #include "zend_vm.h"
39 #include "zend_dtrace.h"
40 #include "zend_inheritance.h"
41 #include "zend_type_info.h"
42 #include "zend_smart_str.h"
43 #include "zend_observer.h"
44 #include "zend_system_id.h"
45 #include "Optimizer/zend_func_info.h"
46 
47 /* Virtual current working directory support */
48 #include "zend_virtual_cwd.h"
49 
50 #ifdef HAVE_GCC_GLOBAL_REGS
51 # if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
52 #  define ZEND_VM_FP_GLOBAL_REG "%esi"
53 #  define ZEND_VM_IP_GLOBAL_REG "%edi"
54 # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
55 #  define ZEND_VM_FP_GLOBAL_REG "%r14"
56 #  define ZEND_VM_IP_GLOBAL_REG "%r15"
57 # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
58 #  define ZEND_VM_FP_GLOBAL_REG "r14"
59 #  define ZEND_VM_IP_GLOBAL_REG "r15"
60 # elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
61 #  define ZEND_VM_FP_GLOBAL_REG "r14"
62 #  define ZEND_VM_IP_GLOBAL_REG "r15"
63 # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__)
64 #  define ZEND_VM_FP_GLOBAL_REG "x27"
65 #  define ZEND_VM_IP_GLOBAL_REG "x28"
66 # endif
67 #endif
68 
69 #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
70 # pragma GCC diagnostic ignored "-Wvolatile-register-var"
71   register zend_execute_data* volatile execute_data __asm__(ZEND_VM_FP_GLOBAL_REG);
72 # pragma GCC diagnostic warning "-Wvolatile-register-var"
73 #endif
74 
75 #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
76 # define EXECUTE_DATA_D     void
77 # define EXECUTE_DATA_C
78 # define EXECUTE_DATA_DC
79 # define EXECUTE_DATA_CC
80 # define NO_EXECUTE_DATA_CC
81 #else
82 # define EXECUTE_DATA_D     zend_execute_data* execute_data
83 # define EXECUTE_DATA_C     execute_data
84 # define EXECUTE_DATA_DC    , EXECUTE_DATA_D
85 # define EXECUTE_DATA_CC    , EXECUTE_DATA_C
86 # define NO_EXECUTE_DATA_CC , NULL
87 #endif
88 
89 #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
90 # define OPLINE_D           void
91 # define OPLINE_C
92 # define OPLINE_DC
93 # define OPLINE_CC
94 #else
95 # define OPLINE_D           const zend_op* opline
96 # define OPLINE_C           opline
97 # define OPLINE_DC          , OPLINE_D
98 # define OPLINE_CC          , OPLINE_C
99 #endif
100 
101 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
102 # pragma GCC diagnostic ignored "-Wvolatile-register-var"
103   register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG);
104 # pragma GCC diagnostic warning "-Wvolatile-register-var"
105 #else
106 #endif
107 
108 #define _CONST_CODE  0
109 #define _TMP_CODE    1
110 #define _VAR_CODE    2
111 #define _UNUSED_CODE 3
112 #define _CV_CODE     4
113 
114 typedef int (ZEND_FASTCALL *incdec_t)(zval *);
115 
116 #define get_zval_ptr(op_type, node, type) _get_zval_ptr(op_type, node, type EXECUTE_DATA_CC OPLINE_CC)
117 #define get_zval_ptr_deref(op_type, node, type) _get_zval_ptr_deref(op_type, node, type EXECUTE_DATA_CC OPLINE_CC)
118 #define get_zval_ptr_undef(op_type, node, type) _get_zval_ptr_undef(op_type, node, type EXECUTE_DATA_CC OPLINE_CC)
119 #define get_op_data_zval_ptr_r(op_type, node) _get_op_data_zval_ptr_r(op_type, node EXECUTE_DATA_CC OPLINE_CC)
120 #define get_op_data_zval_ptr_deref_r(op_type, node) _get_op_data_zval_ptr_deref_r(op_type, node EXECUTE_DATA_CC OPLINE_CC)
121 #define get_zval_ptr_ptr(op_type, node, type) _get_zval_ptr_ptr(op_type, node, type EXECUTE_DATA_CC)
122 #define get_zval_ptr_ptr_undef(op_type, node, type) _get_zval_ptr_ptr(op_type, node, type EXECUTE_DATA_CC)
123 #define get_obj_zval_ptr(op_type, node, type) _get_obj_zval_ptr(op_type, node, type EXECUTE_DATA_CC OPLINE_CC)
124 #define get_obj_zval_ptr_undef(op_type, node, type) _get_obj_zval_ptr_undef(op_type, node, type EXECUTE_DATA_CC OPLINE_CC)
125 #define get_obj_zval_ptr_ptr(op_type, node, type) _get_obj_zval_ptr_ptr(op_type, node, type EXECUTE_DATA_CC)
126 
127 #define RETURN_VALUE_USED(opline) ((opline)->result_type != IS_UNUSED)
128 
ZEND_FUNCTION(pass)129 static ZEND_FUNCTION(pass)
130 {
131 }
132 
133 ZEND_BEGIN_ARG_INFO_EX(zend_pass_function_arg_info, 0, 0, 0)
134 ZEND_END_ARG_INFO()
135 
136 ZEND_API const zend_internal_function zend_pass_function = {
137 	ZEND_INTERNAL_FUNCTION, /* type              */
138 	{0, 0, 0},              /* arg_flags         */
139 	0,                      /* fn_flags          */
140 	NULL,                   /* name              */
141 	NULL,                   /* scope             */
142 	NULL,                   /* prototype         */
143 	0,                      /* num_args          */
144 	0,                      /* required_num_args */
145 	(zend_internal_arg_info *) zend_pass_function_arg_info + 1, /* arg_info */
146 	NULL,                   /* attributes        */
147 	0,                      /* T                 */
148 	NULL,                   /* run_time_cache    */
149 	ZEND_FN(pass),          /* handler           */
150 	NULL,                   /* module            */
151 	{NULL,NULL,NULL,NULL}   /* reserved          */
152 };
153 
154 #define FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_var) do {			\
155 	zval *__container_to_free = EX_VAR(free_var);							\
156 	if (UNEXPECTED(Z_REFCOUNTED_P(__container_to_free))) {					\
157 		zend_refcounted *__ref = Z_COUNTED_P(__container_to_free);			\
158 		if (UNEXPECTED(!GC_DELREF(__ref))) {								\
159 			zval *__zv = EX_VAR(opline->result.var);						\
160 			if (EXPECTED(Z_TYPE_P(__zv) == IS_INDIRECT)) {					\
161 				ZVAL_COPY(__zv, Z_INDIRECT_P(__zv));						\
162 			}																\
163 			rc_dtor_func(__ref);											\
164 		}																	\
165 	}																		\
166 } while (0)
167 
168 #define FREE_OP(type, var) \
169 	if ((type) & (IS_TMP_VAR|IS_VAR)) { \
170 		zval_ptr_dtor_nogc(EX_VAR(var)); \
171 	}
172 
173 #define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
174 
175 #define ZEND_VM_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
176 
177 #define ZEND_VM_STACK_PAGE_SIZE  (ZEND_VM_STACK_PAGE_SLOTS * sizeof(zval))
178 
179 #define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size, page_size) \
180 	(((size) + ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval) \
181 	  + ((page_size) - 1)) & ~((page_size) - 1))
182 
zend_vm_stack_init(void)183 ZEND_API void zend_vm_stack_init(void)
184 {
185 	EG(vm_stack_page_size) = ZEND_VM_STACK_PAGE_SIZE;
186 	EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL);
187 	EG(vm_stack_top) = EG(vm_stack)->top;
188 	EG(vm_stack_end) = EG(vm_stack)->end;
189 }
190 
zend_vm_stack_init_ex(size_t page_size)191 ZEND_API void zend_vm_stack_init_ex(size_t page_size)
192 {
193 	/* page_size must be a power of 2 */
194 	ZEND_ASSERT(page_size > 0 && (page_size & (page_size - 1)) == 0);
195 	EG(vm_stack_page_size) = page_size;
196 	EG(vm_stack) = zend_vm_stack_new_page(page_size, NULL);
197 	EG(vm_stack_top) = EG(vm_stack)->top;
198 	EG(vm_stack_end) = EG(vm_stack)->end;
199 }
200 
zend_vm_stack_destroy(void)201 ZEND_API void zend_vm_stack_destroy(void)
202 {
203 	zend_vm_stack stack = EG(vm_stack);
204 
205 	while (stack != NULL) {
206 		zend_vm_stack p = stack->prev;
207 		efree(stack);
208 		stack = p;
209 	}
210 }
211 
zend_vm_stack_extend(size_t size)212 ZEND_API void* zend_vm_stack_extend(size_t size)
213 {
214 	zend_vm_stack stack;
215 	void *ptr;
216 
217 	stack = EG(vm_stack);
218 	stack->top = EG(vm_stack_top);
219 	EG(vm_stack) = stack = zend_vm_stack_new_page(
220 		EXPECTED(size < EG(vm_stack_page_size) - (ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval))) ?
221 			EG(vm_stack_page_size) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size, EG(vm_stack_page_size)),
222 		stack);
223 	ptr = stack->top;
224 	EG(vm_stack_top) = (void*)(((char*)ptr) + size);
225 	EG(vm_stack_end) = stack->end;
226 	return ptr;
227 }
228 
zend_get_compiled_variable_value(const zend_execute_data * execute_data,uint32_t var)229 ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data, uint32_t var)
230 {
231 	return EX_VAR(var);
232 }
233 
zend_gcc_global_regs(void)234 ZEND_API bool zend_gcc_global_regs(void)
235 {
236   #if defined(HAVE_GCC_GLOBAL_REGS)
237         return 1;
238   #else
239         return 0;
240   #endif
241 }
242 
_get_zval_ptr_tmp(uint32_t var EXECUTE_DATA_DC)243 static zend_always_inline zval *_get_zval_ptr_tmp(uint32_t var EXECUTE_DATA_DC)
244 {
245 	zval *ret = EX_VAR(var);
246 
247 	ZEND_ASSERT(Z_TYPE_P(ret) != IS_REFERENCE);
248 
249 	return ret;
250 }
251 
_get_zval_ptr_var(uint32_t var EXECUTE_DATA_DC)252 static zend_always_inline zval *_get_zval_ptr_var(uint32_t var EXECUTE_DATA_DC)
253 {
254 	zval *ret = EX_VAR(var);
255 
256 	return ret;
257 }
258 
_get_zval_ptr_var_deref(uint32_t var EXECUTE_DATA_DC)259 static zend_always_inline zval *_get_zval_ptr_var_deref(uint32_t var EXECUTE_DATA_DC)
260 {
261 	zval *ret = EX_VAR(var);
262 
263 	ZVAL_DEREF(ret);
264 	return ret;
265 }
266 
zval_undefined_cv(uint32_t var EXECUTE_DATA_DC)267 static zend_never_inline ZEND_COLD zval* zval_undefined_cv(uint32_t var EXECUTE_DATA_DC)
268 {
269 	if (EXPECTED(EG(exception) == NULL)) {
270 		zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
271 		zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
272 	}
273 	return &EG(uninitialized_zval);
274 }
275 
_zval_undefined_op1(EXECUTE_DATA_D)276 static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL _zval_undefined_op1(EXECUTE_DATA_D)
277 {
278 	return zval_undefined_cv(EX(opline)->op1.var EXECUTE_DATA_CC);
279 }
280 
_zval_undefined_op2(EXECUTE_DATA_D)281 static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL _zval_undefined_op2(EXECUTE_DATA_D)
282 {
283 	return zval_undefined_cv(EX(opline)->op2.var EXECUTE_DATA_CC);
284 }
285 
286 #define ZVAL_UNDEFINED_OP1() _zval_undefined_op1(EXECUTE_DATA_C)
287 #define ZVAL_UNDEFINED_OP2() _zval_undefined_op2(EXECUTE_DATA_C)
288 
_get_zval_cv_lookup(zval * ptr,uint32_t var,int type EXECUTE_DATA_DC)289 static zend_never_inline ZEND_COLD zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int type EXECUTE_DATA_DC)
290 {
291 	switch (type) {
292 		case BP_VAR_R:
293 		case BP_VAR_UNSET:
294 			ptr = zval_undefined_cv(var EXECUTE_DATA_CC);
295 			break;
296 		case BP_VAR_IS:
297 			ptr = &EG(uninitialized_zval);
298 			break;
299 		case BP_VAR_RW:
300 			zval_undefined_cv(var EXECUTE_DATA_CC);
301 			ZEND_FALLTHROUGH;
302 		case BP_VAR_W:
303 			ZVAL_NULL(ptr);
304 			break;
305 	}
306 	return ptr;
307 }
308 
_get_zval_ptr_cv(uint32_t var,int type EXECUTE_DATA_DC)309 static zend_always_inline zval *_get_zval_ptr_cv(uint32_t var, int type EXECUTE_DATA_DC)
310 {
311 	zval *ret = EX_VAR(var);
312 
313 	if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
314 		if (type == BP_VAR_W) {
315 			ZVAL_NULL(ret);
316 		} else {
317 			return _get_zval_cv_lookup(ret, var, type EXECUTE_DATA_CC);
318 		}
319 	}
320 	return ret;
321 }
322 
_get_zval_ptr_cv_deref(uint32_t var,int type EXECUTE_DATA_DC)323 static zend_always_inline zval *_get_zval_ptr_cv_deref(uint32_t var, int type EXECUTE_DATA_DC)
324 {
325 	zval *ret = EX_VAR(var);
326 
327 	if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
328 		if (type == BP_VAR_W) {
329 			ZVAL_NULL(ret);
330 			return ret;
331 		} else {
332 			return _get_zval_cv_lookup(ret, var, type EXECUTE_DATA_CC);
333 		}
334 	}
335 	ZVAL_DEREF(ret);
336 	return ret;
337 }
338 
_get_zval_ptr_cv_BP_VAR_R(uint32_t var EXECUTE_DATA_DC)339 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(uint32_t var EXECUTE_DATA_DC)
340 {
341 	zval *ret = EX_VAR(var);
342 
343 	if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
344 		return zval_undefined_cv(var EXECUTE_DATA_CC);
345 	}
346 	return ret;
347 }
348 
_get_zval_ptr_cv_deref_BP_VAR_R(uint32_t var EXECUTE_DATA_DC)349 static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_R(uint32_t var EXECUTE_DATA_DC)
350 {
351 	zval *ret = EX_VAR(var);
352 
353 	if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
354 		return zval_undefined_cv(var EXECUTE_DATA_CC);
355 	}
356 	ZVAL_DEREF(ret);
357 	return ret;
358 }
359 
_get_zval_ptr_cv_BP_VAR_IS(uint32_t var EXECUTE_DATA_DC)360 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(uint32_t var EXECUTE_DATA_DC)
361 {
362 	zval *ret = EX_VAR(var);
363 
364 	return ret;
365 }
366 
_get_zval_ptr_cv_BP_VAR_RW(uint32_t var EXECUTE_DATA_DC)367 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(uint32_t var EXECUTE_DATA_DC)
368 {
369 	zval *ret = EX_VAR(var);
370 
371 	if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
372 		zval_undefined_cv(var EXECUTE_DATA_CC);
373 		ZVAL_NULL(ret);
374 		return ret;
375 	}
376 	return ret;
377 }
378 
_get_zval_ptr_cv_BP_VAR_W(uint32_t var EXECUTE_DATA_DC)379 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(uint32_t var EXECUTE_DATA_DC)
380 {
381 	zval *ret = EX_VAR(var);
382 
383 	if (Z_TYPE_P(ret) == IS_UNDEF) {
384 		ZVAL_NULL(ret);
385 	}
386 	return ret;
387 }
388 
_get_zval_ptr(int op_type,znode_op node,int type EXECUTE_DATA_DC OPLINE_DC)389 static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, int type EXECUTE_DATA_DC OPLINE_DC)
390 {
391 	if (op_type & (IS_TMP_VAR|IS_VAR)) {
392 		if (!ZEND_DEBUG || op_type == IS_VAR) {
393 			return _get_zval_ptr_var(node.var EXECUTE_DATA_CC);
394 		} else {
395 			ZEND_ASSERT(op_type == IS_TMP_VAR);
396 			return _get_zval_ptr_tmp(node.var EXECUTE_DATA_CC);
397 		}
398 	} else {
399 		if (op_type == IS_CONST) {
400 			return RT_CONSTANT(opline, node);
401 		} else if (op_type == IS_CV) {
402 			return _get_zval_ptr_cv(node.var, type EXECUTE_DATA_CC);
403 		} else {
404 			return NULL;
405 		}
406 	}
407 }
408 
_get_op_data_zval_ptr_r(int op_type,znode_op node EXECUTE_DATA_DC OPLINE_DC)409 static zend_always_inline zval *_get_op_data_zval_ptr_r(int op_type, znode_op node EXECUTE_DATA_DC OPLINE_DC)
410 {
411 	if (op_type & (IS_TMP_VAR|IS_VAR)) {
412 		if (!ZEND_DEBUG || op_type == IS_VAR) {
413 			return _get_zval_ptr_var(node.var EXECUTE_DATA_CC);
414 		} else {
415 			ZEND_ASSERT(op_type == IS_TMP_VAR);
416 			return _get_zval_ptr_tmp(node.var EXECUTE_DATA_CC);
417 		}
418 	} else {
419 		if (op_type == IS_CONST) {
420 			return RT_CONSTANT(opline + 1, node);
421 		} else if (op_type == IS_CV) {
422 			return _get_zval_ptr_cv_BP_VAR_R(node.var EXECUTE_DATA_CC);
423 		} else {
424 			return NULL;
425 		}
426 	}
427 }
428 
_get_zval_ptr_deref(int op_type,znode_op node,int type EXECUTE_DATA_DC OPLINE_DC)429 static zend_always_inline ZEND_ATTRIBUTE_UNUSED zval *_get_zval_ptr_deref(int op_type, znode_op node, int type EXECUTE_DATA_DC OPLINE_DC)
430 {
431 	if (op_type & (IS_TMP_VAR|IS_VAR)) {
432 		if (op_type == IS_TMP_VAR) {
433 			return _get_zval_ptr_tmp(node.var EXECUTE_DATA_CC);
434 		} else {
435 			ZEND_ASSERT(op_type == IS_VAR);
436 			return _get_zval_ptr_var_deref(node.var EXECUTE_DATA_CC);
437 		}
438 	} else {
439 		if (op_type == IS_CONST) {
440 			return RT_CONSTANT(opline, node);
441 		} else if (op_type == IS_CV) {
442 			return _get_zval_ptr_cv_deref(node.var, type EXECUTE_DATA_CC);
443 		} else {
444 			return NULL;
445 		}
446 	}
447 }
448 
_get_op_data_zval_ptr_deref_r(int op_type,znode_op node EXECUTE_DATA_DC OPLINE_DC)449 static zend_always_inline ZEND_ATTRIBUTE_UNUSED zval *_get_op_data_zval_ptr_deref_r(int op_type, znode_op node EXECUTE_DATA_DC OPLINE_DC)
450 {
451 	if (op_type & (IS_TMP_VAR|IS_VAR)) {
452 		if (op_type == IS_TMP_VAR) {
453 			return _get_zval_ptr_tmp(node.var EXECUTE_DATA_CC);
454 		} else {
455 			ZEND_ASSERT(op_type == IS_VAR);
456 			return _get_zval_ptr_var_deref(node.var EXECUTE_DATA_CC);
457 		}
458 	} else {
459 		if (op_type == IS_CONST) {
460 			return RT_CONSTANT(opline + 1, node);
461 		} else if (op_type == IS_CV) {
462 			return _get_zval_ptr_cv_deref_BP_VAR_R(node.var EXECUTE_DATA_CC);
463 		} else {
464 			return NULL;
465 		}
466 	}
467 }
468 
_get_zval_ptr_undef(int op_type,znode_op node,int type EXECUTE_DATA_DC OPLINE_DC)469 static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node, int type EXECUTE_DATA_DC OPLINE_DC)
470 {
471 	if (op_type & (IS_TMP_VAR|IS_VAR)) {
472 		if (!ZEND_DEBUG || op_type == IS_VAR) {
473 			return _get_zval_ptr_var(node.var EXECUTE_DATA_CC);
474 		} else {
475 			ZEND_ASSERT(op_type == IS_TMP_VAR);
476 			return _get_zval_ptr_tmp(node.var EXECUTE_DATA_CC);
477 		}
478 	} else {
479 		if (op_type == IS_CONST) {
480 			return RT_CONSTANT(opline, node);
481 		} else if (op_type == IS_CV) {
482 			return EX_VAR(node.var);
483 		} else {
484 			return NULL;
485 		}
486 	}
487 }
488 
_get_zval_ptr_ptr_var(uint32_t var EXECUTE_DATA_DC)489 static zend_always_inline zval *_get_zval_ptr_ptr_var(uint32_t var EXECUTE_DATA_DC)
490 {
491 	zval *ret = EX_VAR(var);
492 
493 	if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
494 		ret = Z_INDIRECT_P(ret);
495 	}
496 	return ret;
497 }
498 
_get_zval_ptr_ptr(int op_type,znode_op node,int type EXECUTE_DATA_DC)499 static inline zval *_get_zval_ptr_ptr(int op_type, znode_op node, int type EXECUTE_DATA_DC)
500 {
501 	if (op_type == IS_CV) {
502 		return _get_zval_ptr_cv(node.var, type EXECUTE_DATA_CC);
503 	} else /* if (op_type == IS_VAR) */ {
504 		ZEND_ASSERT(op_type == IS_VAR);
505 		return _get_zval_ptr_ptr_var(node.var EXECUTE_DATA_CC);
506 	}
507 }
508 
_get_obj_zval_ptr(int op_type,znode_op op,int type EXECUTE_DATA_DC OPLINE_DC)509 static inline ZEND_ATTRIBUTE_UNUSED zval *_get_obj_zval_ptr(int op_type, znode_op op, int type EXECUTE_DATA_DC OPLINE_DC)
510 {
511 	if (op_type == IS_UNUSED) {
512 		return &EX(This);
513 	}
514 	return get_zval_ptr(op_type, op, type);
515 }
516 
_get_obj_zval_ptr_undef(int op_type,znode_op op,int type EXECUTE_DATA_DC OPLINE_DC)517 static inline ZEND_ATTRIBUTE_UNUSED zval *_get_obj_zval_ptr_undef(int op_type, znode_op op, int type EXECUTE_DATA_DC OPLINE_DC)
518 {
519 	if (op_type == IS_UNUSED) {
520 		return &EX(This);
521 	}
522 	return get_zval_ptr_undef(op_type, op, type);
523 }
524 
_get_obj_zval_ptr_ptr(int op_type,znode_op node,int type EXECUTE_DATA_DC)525 static inline ZEND_ATTRIBUTE_UNUSED zval *_get_obj_zval_ptr_ptr(int op_type, znode_op node, int type EXECUTE_DATA_DC)
526 {
527 	if (op_type == IS_UNUSED) {
528 		return &EX(This);
529 	}
530 	return get_zval_ptr_ptr(op_type, node, type);
531 }
532 
zend_assign_to_variable_reference(zval * variable_ptr,zval * value_ptr)533 static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
534 {
535 	zend_reference *ref;
536 
537 	if (EXPECTED(!Z_ISREF_P(value_ptr))) {
538 		ZVAL_NEW_REF(value_ptr, value_ptr);
539 	} else if (UNEXPECTED(variable_ptr == value_ptr)) {
540 		return;
541 	}
542 
543 	ref = Z_REF_P(value_ptr);
544 	GC_ADDREF(ref);
545 	if (Z_REFCOUNTED_P(variable_ptr)) {
546 		zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
547 
548 		if (GC_DELREF(garbage) == 0) {
549 			ZVAL_REF(variable_ptr, ref);
550 			rc_dtor_func(garbage);
551 			return;
552 		} else {
553 			gc_check_possible_root(garbage);
554 		}
555 	}
556 	ZVAL_REF(variable_ptr, ref);
557 }
558 
zend_assign_to_typed_property_reference(zend_property_info * prop_info,zval * prop,zval * value_ptr EXECUTE_DATA_DC)559 static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_property_info *prop_info, zval *prop, zval *value_ptr EXECUTE_DATA_DC)
560 {
561 	if (!zend_verify_prop_assignable_by_ref(prop_info, value_ptr, EX_USES_STRICT_TYPES())) {
562 		return &EG(uninitialized_zval);
563 	}
564 	if (Z_ISREF_P(prop)) {
565 		ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(prop), prop_info);
566 	}
567 	zend_assign_to_variable_reference(prop, value_ptr);
568 	ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(prop), prop_info);
569 	return prop;
570 }
571 
zend_wrong_assign_to_variable_reference(zval * variable_ptr,zval * value_ptr OPLINE_DC EXECUTE_DATA_DC)572 static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
573 {
574 	zend_error(E_NOTICE, "Only variables should be assigned by reference");
575 	if (UNEXPECTED(EG(exception) != NULL)) {
576 		return &EG(uninitialized_zval);
577 	}
578 
579 	/* Use IS_TMP_VAR instead of IS_VAR to avoid ISREF check */
580 	Z_TRY_ADDREF_P(value_ptr);
581 	return zend_assign_to_variable(variable_ptr, value_ptr, IS_TMP_VAR, EX_USES_STRICT_TYPES());
582 }
583 
zend_cannot_pass_by_reference(uint32_t arg_num)584 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num)
585 {
586 	const zend_execute_data *execute_data = EG(current_execute_data);
587 	zend_string *func_name = get_function_or_method_name(EX(call)->func);
588 	const char *param_name = get_function_arg_name(EX(call)->func, arg_num);
589 
590 	zend_throw_error(NULL, "%s(): Argument #%d%s%s%s cannot be passed by reference",
591 		ZSTR_VAL(func_name), arg_num, param_name ? " ($" : "", param_name ? param_name : "", param_name ? ")" : ""
592 	);
593 
594 	zend_string_release(func_name);
595 }
596 
zend_throw_auto_init_in_prop_error(zend_property_info * prop)597 static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error(zend_property_info *prop) {
598 	zend_string *type_str = zend_type_to_string(prop->type);
599 	zend_type_error(
600 		"Cannot auto-initialize an array inside property %s::$%s of type %s",
601 		ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name),
602 		ZSTR_VAL(type_str)
603 	);
604 	zend_string_release(type_str);
605 }
606 
zend_throw_auto_init_in_ref_error(zend_property_info * prop)607 static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_ref_error(zend_property_info *prop) {
608 	zend_string *type_str = zend_type_to_string(prop->type);
609 	zend_type_error(
610 		"Cannot auto-initialize an array inside a reference held by property %s::$%s of type %s",
611 		ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name),
612 		ZSTR_VAL(type_str)
613 	);
614 	zend_string_release(type_str);
615 }
616 
zend_throw_access_uninit_prop_by_ref_error(zend_property_info * prop)617 static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_error(
618 		zend_property_info *prop) {
619 	zend_throw_error(NULL,
620 		"Cannot access uninitialized non-nullable property %s::$%s by reference",
621 		ZSTR_VAL(prop->ce->name),
622 		zend_get_unmangled_property_name(prop->name));
623 }
624 
625 /* this should modify object only if it's empty */
zend_throw_non_object_error(zval * object,zval * property OPLINE_DC EXECUTE_DATA_DC)626 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_error(zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC)
627 {
628 	zend_string *tmp_property_name;
629 	zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
630 
631 	if (opline->opcode == ZEND_PRE_INC_OBJ
632 	 || opline->opcode == ZEND_PRE_DEC_OBJ
633 	 || opline->opcode == ZEND_POST_INC_OBJ
634 	 || opline->opcode == ZEND_POST_DEC_OBJ) {
635 		zend_throw_error(NULL,
636 			"Attempt to increment/decrement property \"%s\" on %s",
637 			ZSTR_VAL(property_name), zend_zval_type_name(object)
638 		);
639 	} else if (opline->opcode == ZEND_FETCH_OBJ_W
640 			|| opline->opcode == ZEND_FETCH_OBJ_RW
641 			|| opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
642 			|| opline->opcode == ZEND_ASSIGN_OBJ_REF) {
643 		zend_throw_error(NULL,
644 			"Attempt to modify property \"%s\" on %s",
645 			ZSTR_VAL(property_name), zend_zval_type_name(object)
646 		);
647 	} else {
648 		zend_throw_error(NULL,
649 			"Attempt to assign property \"%s\" on %s",
650 			ZSTR_VAL(property_name), zend_zval_type_name(object)
651 		);
652 	}
653 	zend_tmp_string_release(tmp_property_name);
654 
655 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
656 		ZVAL_NULL(EX_VAR(opline->result.var));
657 	}
658 }
659 
zend_verify_type_error_common(const zend_function * zf,const zend_arg_info * arg_info,zval * value,const char ** fname,const char ** fsep,const char ** fclass,zend_string ** need_msg,const char ** given_kind)660 static ZEND_COLD void zend_verify_type_error_common(
661 		const zend_function *zf, const zend_arg_info *arg_info, zval *value,
662 		const char **fname, const char **fsep, const char **fclass,
663 		zend_string **need_msg, const char **given_kind)
664 {
665 	*fname = ZSTR_VAL(zf->common.function_name);
666 	if (zf->common.scope) {
667 		*fsep =  "::";
668 		*fclass = ZSTR_VAL(zf->common.scope->name);
669 	} else {
670 		*fsep =  "";
671 		*fclass = "";
672 	}
673 
674 	*need_msg = zend_type_to_string_resolved(arg_info->type, zf->common.scope);
675 
676 	if (value) {
677 		*given_kind = zend_zval_type_name(value);
678 	} else {
679 		*given_kind = "none";
680 	}
681 }
682 
zend_verify_arg_error(const zend_function * zf,const zend_arg_info * arg_info,uint32_t arg_num,zval * value)683 ZEND_API ZEND_COLD void zend_verify_arg_error(
684 		const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *value)
685 {
686 	zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
687 	const char *fname, *fsep, *fclass;
688 	zend_string *need_msg;
689 	const char *given_msg;
690 
691 	zend_verify_type_error_common(
692 		zf, arg_info, value, &fname, &fsep, &fclass, &need_msg, &given_msg);
693 
694 	ZEND_ASSERT(zf->common.type == ZEND_USER_FUNCTION
695 		&& "Arginfo verification is not performed for internal functions");
696 	if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
697 		zend_argument_type_error(arg_num, "must be of type %s, %s given, called in %s on line %d",
698 			ZSTR_VAL(need_msg), given_msg,
699 			ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno
700 		);
701 	} else {
702 		zend_argument_type_error(arg_num,
703 			"must be of type %s, %s given", ZSTR_VAL(need_msg), given_msg);
704 	}
705 
706 	zend_string_release(need_msg);
707 }
708 
zend_verify_weak_scalar_type_hint(uint32_t type_mask,zval * arg)709 static bool zend_verify_weak_scalar_type_hint(uint32_t type_mask, zval *arg)
710 {
711 	zend_long lval;
712 	double dval;
713 	zend_string *str;
714 	bool bval;
715 
716 	/* Type preference order: int -> float -> string -> bool */
717 	if (type_mask & MAY_BE_LONG) {
718 		/* For an int|float union type and string value,
719 		 * determine chosen type by is_numeric_string() semantics. */
720 		if ((type_mask & MAY_BE_DOUBLE) && Z_TYPE_P(arg) == IS_STRING) {
721 			zend_uchar type = is_numeric_str_function(Z_STR_P(arg), &lval, &dval);
722 			if (type == IS_LONG) {
723 				zend_string_release(Z_STR_P(arg));
724 				ZVAL_LONG(arg, lval);
725 				return 1;
726 			}
727 			if (type == IS_DOUBLE) {
728 				zend_string_release(Z_STR_P(arg));
729 				ZVAL_DOUBLE(arg, dval);
730 				return 1;
731 			}
732 		} else if (zend_parse_arg_long_weak(arg, &lval, 0)) {
733 			zval_ptr_dtor(arg);
734 			ZVAL_LONG(arg, lval);
735 			return 1;
736 		} else if (UNEXPECTED(EG(exception))) {
737 			return 0;
738 		}
739 	}
740 	if ((type_mask & MAY_BE_DOUBLE) && zend_parse_arg_double_weak(arg, &dval, 0)) {
741 		zval_ptr_dtor(arg);
742 		ZVAL_DOUBLE(arg, dval);
743 		return 1;
744 	}
745 	if ((type_mask & MAY_BE_STRING) && zend_parse_arg_str_weak(arg, &str, 0)) {
746 		/* on success "arg" is converted to IS_STRING */
747 		return 1;
748 	}
749 	if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL && zend_parse_arg_bool_weak(arg, &bval, 0)) {
750 		zval_ptr_dtor(arg);
751 		ZVAL_BOOL(arg, bval);
752 		return 1;
753 	}
754 	return 0;
755 }
756 
757 #if ZEND_DEBUG
can_convert_to_string(zval * zv)758 static bool can_convert_to_string(zval *zv) {
759 	/* We don't call cast_object here, because this check must be side-effect free. As this
760 	 * is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept
761 	 * more than actually allowed here. */
762 	if (Z_TYPE_P(zv) == IS_OBJECT) {
763 		return Z_OBJ_HT_P(zv)->cast_object != zend_std_cast_object_tostring
764 			|| Z_OBJCE_P(zv)->__tostring;
765 	}
766 	return Z_TYPE_P(zv) <= IS_STRING;
767 }
768 
769 /* Used to sanity-check internal arginfo types without performing any actual type conversions. */
zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_mask,zval * arg)770 static bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_mask, zval *arg)
771 {
772 	zend_long lval;
773 	double dval;
774 	bool bval;
775 
776 	/* Pass (uint32_t)-1 as arg_num to indicate to ZPP not to emit any deprecation notice,
777 	 * this is needed because the version with side effects also uses 0 (e.g. for typed properties) */
778 	if ((type_mask & MAY_BE_LONG) && zend_parse_arg_long_weak(arg, &lval, (uint32_t)-1)) {
779 		return 1;
780 	}
781 	if ((type_mask & MAY_BE_DOUBLE) && zend_parse_arg_double_weak(arg, &dval, (uint32_t)-1)) {
782 		return 1;
783 	}
784 	if ((type_mask & MAY_BE_STRING) && can_convert_to_string(arg)) {
785 		return 1;
786 	}
787 	if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL && zend_parse_arg_bool_weak(arg, &bval, (uint32_t)-1)) {
788 		return 1;
789 	}
790 	return 0;
791 }
792 #endif
793 
zend_verify_scalar_type_hint(uint32_t type_mask,zval * arg,bool strict,bool is_internal_arg)794 ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool strict, bool is_internal_arg)
795 {
796 	if (UNEXPECTED(strict)) {
797 		/* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
798 		if (!(type_mask & MAY_BE_DOUBLE) || Z_TYPE_P(arg) != IS_LONG) {
799 			return 0;
800 		}
801 	} else if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
802 		/* NULL may be accepted only by nullable hints (this is already checked).
803 		 * As an exception for internal functions, null is allowed for scalar types in weak mode. */
804 		return is_internal_arg
805 			&& (type_mask & (MAY_BE_TRUE|MAY_BE_FALSE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING));
806 	}
807 #if ZEND_DEBUG
808 	if (is_internal_arg) {
809 		return zend_verify_weak_scalar_type_hint_no_sideeffect(type_mask, arg);
810 	}
811 #endif
812 	return zend_verify_weak_scalar_type_hint(type_mask, arg);
813 }
814 
zend_verify_property_type_error(zend_property_info * info,zval * property)815 ZEND_COLD zend_never_inline void zend_verify_property_type_error(zend_property_info *info, zval *property)
816 {
817 	zend_string *type_str;
818 
819 	/* we _may_ land here in case reading already errored and runtime cache thus has not been updated (i.e. it contains a valid but unrelated info) */
820 	if (EG(exception)) {
821 		return;
822 	}
823 
824 	type_str = zend_type_to_string(info->type);
825 	zend_type_error("Cannot assign %s to property %s::$%s of type %s",
826 		zend_zval_type_name(property),
827 		ZSTR_VAL(info->ce->name),
828 		zend_get_unmangled_property_name(info->name),
829 		ZSTR_VAL(type_str));
830 	zend_string_release(type_str);
831 }
832 
zend_match_unhandled_error(zval * value)833 ZEND_COLD void zend_match_unhandled_error(zval *value)
834 {
835 	smart_str msg = {0};
836 
837 	if (Z_TYPE_P(value) <= IS_STRING) {
838 		smart_str_append_scalar(&msg, value, EG(exception_string_param_max_len));
839 	} else {
840 		smart_str_appendl(&msg, "of type ", sizeof("of type ")-1);
841 		smart_str_appends(&msg, zend_zval_type_name(value));
842 	}
843 
844 	smart_str_0(&msg);
845 
846 	zend_throw_exception_ex(
847 		zend_ce_unhandled_match_error, 0, "Unhandled match case %s", ZSTR_VAL(msg.s));
848 
849 	smart_str_free(&msg);
850 }
851 
zend_readonly_property_modification_error(zend_property_info * info)852 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(
853 		zend_property_info *info) {
854 	zend_throw_error(NULL, "Cannot modify readonly property %s::$%s",
855 		ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name));
856 }
857 
zend_readonly_property_indirect_modification_error(zend_property_info * info)858 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(zend_property_info *info)
859 {
860 	zend_throw_error(NULL, "Cannot indirectly modify readonly property %s::$%s",
861 		ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name));
862 }
863 
resolve_single_class_type(zend_string * name,zend_class_entry * self_ce)864 static zend_class_entry *resolve_single_class_type(zend_string *name, zend_class_entry *self_ce) {
865 	if (zend_string_equals_literal_ci(name, "self")) {
866 		return self_ce;
867 	} else if (zend_string_equals_literal_ci(name, "parent")) {
868 		return self_ce->parent;
869 	} else {
870 		return zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
871 	}
872 }
873 
zend_ce_from_type(zend_property_info * info,zend_type * type)874 static zend_always_inline zend_class_entry *zend_ce_from_type(
875 		zend_property_info *info, zend_type *type) {
876 	ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*type));
877 	zend_string *name = ZEND_TYPE_NAME(*type);
878 	if (ZSTR_HAS_CE_CACHE(name)) {
879 		zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
880 		if (!ce) {
881 			ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
882 		}
883 		return ce;
884 	}
885 	return resolve_single_class_type(name, info->ce);
886 }
887 
zend_check_intersection_for_property_class_type(zend_type_list * intersection_type_list,zend_property_info * info,zend_class_entry * object_ce)888 static bool zend_check_intersection_for_property_class_type(zend_type_list *intersection_type_list,
889 	zend_property_info *info, zend_class_entry *object_ce)
890 {
891 	zend_type *list_type;
892 
893 	ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) {
894 		ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
895 		zend_class_entry *ce = zend_ce_from_type(info, list_type);
896 		if (!ce || !instanceof_function(object_ce, ce)) {
897 			return false;
898 		}
899 	} ZEND_TYPE_LIST_FOREACH_END();
900 	return true;
901 }
902 
zend_check_and_resolve_property_class_type(zend_property_info * info,zend_class_entry * object_ce)903 static bool zend_check_and_resolve_property_class_type(
904 		zend_property_info *info, zend_class_entry *object_ce) {
905 	if (ZEND_TYPE_HAS_LIST(info->type)) {
906 		zend_type *list_type;
907 		if (ZEND_TYPE_IS_INTERSECTION(info->type)) {
908 			return zend_check_intersection_for_property_class_type(
909 				ZEND_TYPE_LIST(info->type), info, object_ce);
910 		} else {
911 			ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(info->type), list_type) {
912 				if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
913 					if (zend_check_intersection_for_property_class_type(
914 							ZEND_TYPE_LIST(*list_type), info, object_ce)) {
915 						return true;
916                     }
917 					continue;
918 				}
919 				ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
920 				zend_class_entry *ce = zend_ce_from_type(info, list_type);
921 				if (ce && instanceof_function(object_ce, ce)) {
922 					return true;
923 				}
924 			} ZEND_TYPE_LIST_FOREACH_END();
925 			return false;
926 		}
927 	} else {
928 		zend_class_entry *ce = zend_ce_from_type(info, &info->type);
929 		return ce && instanceof_function(object_ce, ce);
930 	}
931 }
932 
i_zend_check_property_type(zend_property_info * info,zval * property,bool strict)933 static zend_always_inline bool i_zend_check_property_type(zend_property_info *info, zval *property, bool strict)
934 {
935 	ZEND_ASSERT(!Z_ISREF_P(property));
936 	if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(info->type, Z_TYPE_P(property)))) {
937 		return 1;
938 	}
939 
940 	if (ZEND_TYPE_IS_COMPLEX(info->type) && Z_TYPE_P(property) == IS_OBJECT
941 			&& zend_check_and_resolve_property_class_type(info, Z_OBJCE_P(property))) {
942 		return 1;
943 	}
944 
945 	uint32_t type_mask = ZEND_TYPE_FULL_MASK(info->type);
946 	ZEND_ASSERT(!(type_mask & (MAY_BE_CALLABLE|MAY_BE_STATIC)));
947 	return zend_verify_scalar_type_hint(type_mask, property, strict, 0);
948 }
949 
i_zend_verify_property_type(zend_property_info * info,zval * property,bool strict)950 static zend_always_inline bool i_zend_verify_property_type(zend_property_info *info, zval *property, bool strict)
951 {
952 	if (i_zend_check_property_type(info, property, strict)) {
953 		return 1;
954 	}
955 
956 	zend_verify_property_type_error(info, property);
957 	return 0;
958 }
959 
zend_verify_property_type(zend_property_info * info,zval * property,bool strict)960 ZEND_API bool zend_never_inline zend_verify_property_type(zend_property_info *info, zval *property, bool strict) {
961 	return i_zend_verify_property_type(info, property, strict);
962 }
963 
zend_assign_to_typed_prop(zend_property_info * info,zval * property_val,zval * value EXECUTE_DATA_DC)964 static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *info, zval *property_val, zval *value EXECUTE_DATA_DC)
965 {
966 	zval tmp;
967 
968 	if (UNEXPECTED(info->flags & ZEND_ACC_READONLY)) {
969 		zend_readonly_property_modification_error(info);
970 		return &EG(uninitialized_zval);
971 	}
972 
973 	ZVAL_DEREF(value);
974 	ZVAL_COPY(&tmp, value);
975 
976 	if (UNEXPECTED(!i_zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
977 		zval_ptr_dtor(&tmp);
978 		return &EG(uninitialized_zval);
979 	}
980 
981 	return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
982 }
983 
zend_value_instanceof_static(zval * zv)984 static zend_always_inline bool zend_value_instanceof_static(zval *zv) {
985 	if (Z_TYPE_P(zv) != IS_OBJECT) {
986 		return 0;
987 	}
988 
989 	zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data));
990 	if (!called_scope) {
991 		return 0;
992 	}
993 	return instanceof_function(Z_OBJCE_P(zv), called_scope);
994 }
995 
996 /* The cache_slot may only be NULL in debug builds, where arginfo verification of
997  * internal functions is enabled. Avoid unnecessary checks in release builds. */
998 #if ZEND_DEBUG
999 # define HAVE_CACHE_SLOT (cache_slot != NULL)
1000 #else
1001 # define HAVE_CACHE_SLOT 1
1002 #endif
1003 
1004 #define PROGRESS_CACHE_SLOT() if (HAVE_CACHE_SLOT) {cache_slot++;}
1005 
zend_fetch_ce_from_cache_slot(void ** cache_slot,zend_type * type)1006 static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot(
1007 		void **cache_slot, zend_type *type)
1008 {
1009 	if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
1010 		return (zend_class_entry *) *cache_slot;
1011 	}
1012 
1013 	zend_string *name = ZEND_TYPE_NAME(*type);
1014 	zend_class_entry *ce;
1015 	if (ZSTR_HAS_CE_CACHE(name)) {
1016 		ce = ZSTR_GET_CE_CACHE(name);
1017 		if (!ce) {
1018 			ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
1019 			if (UNEXPECTED(!ce)) {
1020 				/* Cannot resolve */
1021 				return NULL;
1022 			}
1023 		}
1024 	} else {
1025 		ce = zend_fetch_class(name,
1026 			ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
1027 		if (UNEXPECTED(!ce)) {
1028 			return NULL;
1029 		}
1030 	}
1031 	if (HAVE_CACHE_SLOT) {
1032 		*cache_slot = (void *) ce;
1033 	}
1034 	return ce;
1035 }
1036 
zend_check_intersection_type_from_cache_slot(zend_type_list * intersection_type_list,zend_class_entry * arg_ce,void *** cache_slot_ptr)1037 static bool zend_check_intersection_type_from_cache_slot(zend_type_list *intersection_type_list,
1038 	zend_class_entry *arg_ce, void ***cache_slot_ptr)
1039 {
1040 	void **cache_slot = *cache_slot_ptr;
1041 	zend_class_entry *ce;
1042 	zend_type *list_type;
1043 	bool status = true;
1044 	ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) {
1045 		/* Only check classes if the type might be valid */
1046 		if (status) {
1047 			ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
1048 			/* If type is not an instance of one of the types taking part in the
1049 			 * intersection it cannot be a valid instance of the whole intersection type. */
1050 			if (!ce || !instanceof_function(arg_ce, ce)) {
1051 				status = false;
1052 			}
1053 		}
1054 		PROGRESS_CACHE_SLOT();
1055 	} ZEND_TYPE_LIST_FOREACH_END();
1056 	if (HAVE_CACHE_SLOT) {
1057 		*cache_slot_ptr = cache_slot;
1058 	}
1059 	return status;
1060 }
1061 
zend_check_type_slow(zend_type * type,zval * arg,zend_reference * ref,void ** cache_slot,bool is_return_type,bool is_internal)1062 static zend_always_inline bool zend_check_type_slow(
1063 		zend_type *type, zval *arg, zend_reference *ref, void **cache_slot,
1064 		bool is_return_type, bool is_internal)
1065 {
1066 	uint32_t type_mask;
1067 	if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
1068 		zend_class_entry *ce;
1069 		if (UNEXPECTED(ZEND_TYPE_HAS_LIST(*type))) {
1070 			zend_type *list_type;
1071 			if (ZEND_TYPE_IS_INTERSECTION(*type)) {
1072 				return zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot);
1073 			} else {
1074 				ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
1075 					if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
1076 						if (zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) {
1077 							return true;
1078 						}
1079 						/* The cache_slot is progressed in zend_check_intersection_type_from_cache_slot() */
1080 					} else {
1081 						ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
1082 						ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
1083 						/* Instance of a single type part of a union is sufficient to pass the type check */
1084 						if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
1085 							return true;
1086 						}
1087 						PROGRESS_CACHE_SLOT();
1088 					}
1089 				} ZEND_TYPE_LIST_FOREACH_END();
1090 			}
1091 		} else {
1092 			ce = zend_fetch_ce_from_cache_slot(cache_slot, type);
1093 			/* If we have a CE we check if it satisfies the type constraint,
1094 			 * otherwise it will check if a standard type satisfies it. */
1095 			if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
1096 				return true;
1097 			}
1098 		}
1099 	}
1100 
1101 	type_mask = ZEND_TYPE_FULL_MASK(*type);
1102 	if ((type_mask & MAY_BE_CALLABLE) &&
1103 		zend_is_callable(arg, is_internal ? IS_CALLABLE_SUPPRESS_DEPRECATIONS : 0, NULL)) {
1104 		return 1;
1105 	}
1106 	if ((type_mask & MAY_BE_STATIC) && zend_value_instanceof_static(arg)) {
1107 		return 1;
1108 	}
1109 	if (ref && ZEND_REF_HAS_TYPE_SOURCES(ref)) {
1110 		/* We cannot have conversions for typed refs. */
1111 		return 0;
1112 	}
1113 	if (is_internal && is_return_type) {
1114 		/* For internal returns, the type has to match exactly, because we're not
1115 		 * going to check it for non-debug builds, and there will be no chance to
1116 		 * apply coercions. */
1117 		return 0;
1118 	}
1119 
1120 	return zend_verify_scalar_type_hint(type_mask, arg,
1121 		is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES(),
1122 		is_internal);
1123 
1124 	/* Special handling for IS_VOID is not necessary (for return types),
1125 	 * because this case is already checked at compile-time. */
1126 }
1127 
zend_check_type(zend_type * type,zval * arg,void ** cache_slot,zend_class_entry * scope,bool is_return_type,bool is_internal)1128 static zend_always_inline bool zend_check_type(
1129 		zend_type *type, zval *arg, void **cache_slot, zend_class_entry *scope,
1130 		bool is_return_type, bool is_internal)
1131 {
1132 	zend_reference *ref = NULL;
1133 	ZEND_ASSERT(ZEND_TYPE_IS_SET(*type));
1134 
1135 	if (UNEXPECTED(Z_ISREF_P(arg))) {
1136 		ref = Z_REF_P(arg);
1137 		arg = Z_REFVAL_P(arg);
1138 	}
1139 
1140 	if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(*type, Z_TYPE_P(arg)))) {
1141 		return 1;
1142 	}
1143 
1144 	return zend_check_type_slow(type, arg, ref, cache_slot, is_return_type, is_internal);
1145 }
1146 
zend_check_user_type_slow(zend_type * type,zval * arg,zend_reference * ref,void ** cache_slot,bool is_return_type)1147 ZEND_API bool zend_check_user_type_slow(
1148 		zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, bool is_return_type)
1149 {
1150 	return zend_check_type_slow(
1151 		type, arg, ref, cache_slot, is_return_type, /* is_internal */ false);
1152 }
1153 
zend_verify_recv_arg_type(zend_function * zf,uint32_t arg_num,zval * arg,void ** cache_slot)1154 static zend_always_inline bool zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot)
1155 {
1156 	zend_arg_info *cur_arg_info;
1157 
1158 	ZEND_ASSERT(arg_num <= zf->common.num_args);
1159 	cur_arg_info = &zf->common.arg_info[arg_num-1];
1160 
1161 	if (ZEND_TYPE_IS_SET(cur_arg_info->type)
1162 			&& UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) {
1163 		zend_verify_arg_error(zf, cur_arg_info, arg_num, arg);
1164 		return 0;
1165 	}
1166 
1167 	return 1;
1168 }
1169 
zend_verify_variadic_arg_type(zend_function * zf,zend_arg_info * arg_info,uint32_t arg_num,zval * arg,void ** cache_slot)1170 static zend_always_inline bool zend_verify_variadic_arg_type(
1171 		zend_function *zf, zend_arg_info *arg_info, uint32_t arg_num, zval *arg, void **cache_slot)
1172 {
1173 	ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
1174 	if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) {
1175 		zend_verify_arg_error(zf, arg_info, arg_num, arg);
1176 		return 0;
1177 	}
1178 
1179 	return 1;
1180 }
1181 
zend_verify_internal_arg_types(zend_function * fbc,zend_execute_data * call)1182 static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call)
1183 {
1184 	uint32_t i;
1185 	uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
1186 	zval *arg = ZEND_CALL_ARG(call, 1);
1187 
1188 	for (i = 0; i < num_args; ++i) {
1189 		zend_arg_info *cur_arg_info;
1190 		if (EXPECTED(i < fbc->common.num_args)) {
1191 			cur_arg_info = &fbc->common.arg_info[i];
1192 		} else if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
1193 			cur_arg_info = &fbc->common.arg_info[fbc->common.num_args];
1194 		} else {
1195 			break;
1196 		}
1197 
1198 		if (ZEND_TYPE_IS_SET(cur_arg_info->type)
1199 				&& UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) {
1200 			return 0;
1201 		}
1202 		arg++;
1203 	}
1204 	return 1;
1205 }
1206 
1207 #if ZEND_DEBUG
1208 /* Determine whether an internal call should throw, because the passed arguments violate
1209  * an arginfo constraint. This is only checked in debug builds. In release builds, we
1210  * trust that arginfo matches what is enforced by zend_parse_parameters. */
zend_internal_call_should_throw(zend_function * fbc,zend_execute_data * call)1211 ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call)
1212 {
1213 	if (fbc->internal_function.handler == ZEND_FN(pass) || (fbc->internal_function.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
1214 		/* Be lenient about the special pass function and about fake closures. */
1215 		return 0;
1216 	}
1217 
1218 	if (fbc->common.required_num_args > ZEND_CALL_NUM_ARGS(call)) {
1219 		/* Required argument not passed. */
1220 		return 1;
1221 	}
1222 
1223 	if (fbc->common.num_args < ZEND_CALL_NUM_ARGS(call)
1224 			&& !(fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
1225 		/* Too many arguments passed. For internal functions (unlike userland functions),
1226 		 * this should always throw. */
1227 		return 1;
1228 	}
1229 
1230 	if ((fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) &&
1231 			!zend_verify_internal_arg_types(fbc, call)) {
1232 		return 1;
1233 	}
1234 
1235 	return 0;
1236 }
1237 
zend_internal_call_arginfo_violation(zend_function * fbc)1238 ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc)
1239 {
1240 	zend_error(E_ERROR, "Arginfo / zpp mismatch during call of %s%s%s()",
1241 		fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "",
1242 		fbc->common.scope ? "::" : "",
1243 		ZSTR_VAL(fbc->common.function_name));
1244 }
1245 
1246 #ifndef ZEND_VERIFY_FUNC_INFO
1247 # define ZEND_VERIFY_FUNC_INFO 0
1248 #endif
1249 
zend_verify_internal_func_info(zend_function * fn,zval * retval)1250 static void zend_verify_internal_func_info(zend_function *fn, zval *retval) {
1251 #if ZEND_VERIFY_FUNC_INFO
1252 	zend_string *name = fn->common.function_name;
1253 	uint32_t type_mask = zend_get_internal_func_info(fn, NULL, NULL);
1254 	if (!type_mask) {
1255 		return;
1256 	}
1257 
1258 	/* Always check refcount of arrays, as immutable arrays are RCN. */
1259 	if (Z_REFCOUNTED_P(retval) || Z_TYPE_P(retval) == IS_ARRAY) {
1260 		if (!(type_mask & MAY_BE_RC1)) {
1261 			zend_error_noreturn(E_CORE_ERROR, "%s() missing rc1", ZSTR_VAL(name));
1262 		}
1263 		if (Z_REFCOUNT_P(retval) > 1 && !(type_mask & MAY_BE_RCN)) {
1264 			zend_error_noreturn(E_CORE_ERROR, "%s() missing rcn", ZSTR_VAL(name));
1265 		}
1266 	}
1267 
1268 	uint32_t type = 1u << Z_TYPE_P(retval);
1269 	if (!(type_mask & type)) {
1270 		zend_error_noreturn(E_CORE_ERROR, "%s() missing type %s",
1271 			ZSTR_VAL(name), zend_get_type_by_const(Z_TYPE_P(retval)));
1272 	}
1273 
1274 	if (Z_TYPE_P(retval) == IS_ARRAY) {
1275 		HashTable *ht = Z_ARRVAL_P(retval);
1276 		uint32_t num_checked = 0;
1277 		zend_string *str;
1278 		zval *val;
1279 		ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
1280 			if (str) {
1281 				if (!(type_mask & MAY_BE_ARRAY_KEY_STRING)) {
1282 					zend_error_noreturn(E_CORE_ERROR,
1283 						"%s() missing array_key_string", ZSTR_VAL(name));
1284 				}
1285 			} else {
1286 				if (!(type_mask & MAY_BE_ARRAY_KEY_LONG)) {
1287 					zend_error_noreturn(E_CORE_ERROR,
1288 						"%s() missing array_key_long", ZSTR_VAL(name));
1289 				}
1290 			}
1291 
1292 			uint32_t array_type = 1u << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
1293 			if (!(type_mask & array_type)) {
1294 				zend_error_noreturn(E_CORE_ERROR,
1295 					"%s() missing array element type %s",
1296 					ZSTR_VAL(name), zend_get_type_by_const(Z_TYPE_P(retval)));
1297 			}
1298 
1299 			/* Don't check all elements of large arrays. */
1300 			if (++num_checked > 16) {
1301 				break;
1302 			}
1303 		} ZEND_HASH_FOREACH_END();
1304 	}
1305 #endif
1306 }
1307 #endif
1308 
zend_missing_arg_error(zend_execute_data * execute_data)1309 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data)
1310 {
1311 	zend_execute_data *ptr = EX(prev_execute_data);
1312 
1313 	if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
1314 		zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected",
1315 			EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "",
1316 			EX(func)->common.scope ? "::" : "",
1317 			ZSTR_VAL(EX(func)->common.function_name),
1318 			EX_NUM_ARGS(),
1319 			ZSTR_VAL(ptr->func->op_array.filename),
1320 			ptr->opline->lineno,
1321 			EX(func)->common.required_num_args == EX(func)->common.num_args ? "exactly" : "at least",
1322 			EX(func)->common.required_num_args);
1323 	} else {
1324 		zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed and %s %d expected",
1325 			EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "",
1326 			EX(func)->common.scope ? "::" : "",
1327 			ZSTR_VAL(EX(func)->common.function_name),
1328 			EX_NUM_ARGS(),
1329 			EX(func)->common.required_num_args == EX(func)->common.num_args ? "exactly" : "at least",
1330 			EX(func)->common.required_num_args);
1331 	}
1332 }
1333 
zend_verify_return_error(const zend_function * zf,zval * value)1334 ZEND_API ZEND_COLD void zend_verify_return_error(const zend_function *zf, zval *value)
1335 {
1336 	const zend_arg_info *arg_info = &zf->common.arg_info[-1];
1337 	const char *fname, *fsep, *fclass;
1338 	zend_string *need_msg;
1339 	const char *given_msg;
1340 
1341 	zend_verify_type_error_common(
1342 		zf, arg_info, value, &fname, &fsep, &fclass, &need_msg, &given_msg);
1343 
1344 	zend_type_error("%s%s%s(): Return value must be of type %s, %s returned",
1345 		fclass, fsep, fname, ZSTR_VAL(need_msg), given_msg);
1346 
1347 	zend_string_release(need_msg);
1348 }
1349 
zend_verify_never_error(const zend_function * zf)1350 ZEND_API ZEND_COLD void zend_verify_never_error(const zend_function *zf)
1351 {
1352 	zend_string *func_name = get_function_or_method_name(zf);
1353 
1354 	zend_type_error("%s(): never-returning function must not implicitly return",
1355 		ZSTR_VAL(func_name));
1356 
1357 	zend_string_release(func_name);
1358 }
1359 
1360 #if ZEND_DEBUG
zend_verify_internal_return_error(const zend_function * zf,zval * value)1361 static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, zval *value)
1362 {
1363 	const zend_arg_info *arg_info = &zf->common.arg_info[-1];
1364 	const char *fname, *fsep, *fclass;
1365 	zend_string *need_msg;
1366 	const char *given_msg;
1367 
1368 	zend_verify_type_error_common(
1369 		zf, arg_info, value, &fname, &fsep, &fclass, &need_msg, &given_msg);
1370 
1371 	zend_error_noreturn(E_CORE_ERROR, "%s%s%s(): Return value must be of type %s, %s returned",
1372 		fclass, fsep, fname, ZSTR_VAL(need_msg), given_msg);
1373 }
1374 
zend_verify_void_return_error(const zend_function * zf,const char * returned_msg,const char * returned_kind)1375 static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, const char *returned_msg, const char *returned_kind)
1376 {
1377 	const char *fname = ZSTR_VAL(zf->common.function_name);
1378 	const char *fsep;
1379 	const char *fclass;
1380 
1381 	if (zf->common.scope) {
1382 		fsep =  "::";
1383 		fclass = ZSTR_VAL(zf->common.scope->name);
1384 	} else {
1385 		fsep =  "";
1386 		fclass = "";
1387 	}
1388 
1389 	zend_type_error("%s%s%s() must not return a value, %s%s returned",
1390 		fclass, fsep, fname, returned_msg, returned_kind);
1391 }
1392 
zend_verify_internal_return_type(zend_function * zf,zval * ret)1393 ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
1394 {
1395 	zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1;
1396 
1397 	if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) {
1398 		if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) {
1399 			zend_verify_void_return_error(zf, zend_zval_type_name(ret), "");
1400 			return 0;
1401 		}
1402 		return 1;
1403 	}
1404 
1405 	if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) {
1406 		zend_verify_internal_return_error(zf, ret);
1407 		return 0;
1408 	}
1409 
1410 	return 1;
1411 }
1412 #endif
1413 
zend_verify_missing_return_type(const zend_function * zf)1414 static ZEND_COLD void zend_verify_missing_return_type(const zend_function *zf)
1415 {
1416 	/* VERIFY_RETURN_TYPE is not emitted for "void" functions, so this is always an error. */
1417 	zend_verify_return_error(zf, NULL);
1418 }
1419 
zend_use_object_as_array(const zend_object * object)1420 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_object_as_array(const zend_object *object)
1421 {
1422 	zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(object->ce->name));
1423 }
1424 
zend_illegal_offset(void)1425 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_offset(void)
1426 {
1427 	zend_type_error("Illegal offset type");
1428 }
1429 
zend_illegal_string_offset(const zval * offset)1430 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_string_offset(const zval *offset)
1431 {
1432 	zend_type_error("Cannot access offset of type %s on string", zend_zval_type_name(offset));
1433 }
1434 
zend_assign_to_object_dim(zend_object * obj,zval * dim,zval * value OPLINE_DC EXECUTE_DATA_DC)1435 static zend_never_inline void zend_assign_to_object_dim(zend_object *obj, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC)
1436 {
1437 	obj->handlers->write_dimension(obj, dim, value);
1438 
1439 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1440 		ZVAL_COPY(EX_VAR(opline->result.var), value);
1441 	}
1442 }
1443 
zend_binary_op(zval * ret,zval * op1,zval * op2 OPLINE_DC)1444 static zend_always_inline int zend_binary_op(zval *ret, zval *op1, zval *op2 OPLINE_DC)
1445 {
1446 	static const binary_op_type zend_binary_ops[] = {
1447 		add_function,
1448 		sub_function,
1449 		mul_function,
1450 		div_function,
1451 		mod_function,
1452 		shift_left_function,
1453 		shift_right_function,
1454 		concat_function,
1455 		bitwise_or_function,
1456 		bitwise_and_function,
1457 		bitwise_xor_function,
1458 		pow_function
1459 	};
1460 	/* size_t cast makes GCC to better optimize 64-bit PIC code */
1461 	size_t opcode = (size_t)opline->extended_value;
1462 
1463 	return zend_binary_ops[opcode - ZEND_ADD](ret, op1, op2);
1464 }
1465 
zend_binary_assign_op_obj_dim(zend_object * obj,zval * property OPLINE_DC EXECUTE_DATA_DC)1466 static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zval *property OPLINE_DC EXECUTE_DATA_DC)
1467 {
1468 	zval *value;
1469 	zval *z;
1470 	zval rv, res;
1471 
1472 	GC_ADDREF(obj);
1473 	if (property && UNEXPECTED(Z_ISUNDEF_P(property))) {
1474 		property = ZVAL_UNDEFINED_OP2();
1475 	}
1476 	value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1);
1477 	if ((z = obj->handlers->read_dimension(obj, property, BP_VAR_R, &rv)) != NULL) {
1478 
1479 		if (zend_binary_op(&res, z, value OPLINE_CC) == SUCCESS) {
1480 			obj->handlers->write_dimension(obj, property, &res);
1481 		}
1482 		if (z == &rv) {
1483 			zval_ptr_dtor(&rv);
1484 		}
1485 		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1486 			ZVAL_COPY(EX_VAR(opline->result.var), &res);
1487 		}
1488 		zval_ptr_dtor(&res);
1489 	} else {
1490 		zend_use_object_as_array(obj);
1491 		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1492 			ZVAL_NULL(EX_VAR(opline->result.var));
1493 		}
1494 	}
1495 	FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
1496 	if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1497 		zend_objects_store_del(obj);
1498 	}
1499 }
1500 
zend_binary_assign_op_typed_ref(zend_reference * ref,zval * value OPLINE_DC EXECUTE_DATA_DC)1501 static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *ref, zval *value OPLINE_DC EXECUTE_DATA_DC)
1502 {
1503 	zval z_copy;
1504 
1505 	/* Make sure that in-place concatenation is used if the LHS is a string. */
1506 	if (opline->extended_value == ZEND_CONCAT && Z_TYPE(ref->val) == IS_STRING) {
1507 		concat_function(&ref->val, &ref->val, value);
1508 		ZEND_ASSERT(Z_TYPE(ref->val) == IS_STRING && "Concat should return string");
1509 		return;
1510 	}
1511 
1512 	zend_binary_op(&z_copy, &ref->val, value OPLINE_CC);
1513 	if (EXPECTED(zend_verify_ref_assignable_zval(ref, &z_copy, EX_USES_STRICT_TYPES()))) {
1514 		zval_ptr_dtor(&ref->val);
1515 		ZVAL_COPY_VALUE(&ref->val, &z_copy);
1516 	} else {
1517 		zval_ptr_dtor(&z_copy);
1518 	}
1519 }
1520 
zend_binary_assign_op_typed_prop(zend_property_info * prop_info,zval * zptr,zval * value OPLINE_DC EXECUTE_DATA_DC)1521 static zend_never_inline void zend_binary_assign_op_typed_prop(zend_property_info *prop_info, zval *zptr, zval *value OPLINE_DC EXECUTE_DATA_DC)
1522 {
1523 	zval z_copy;
1524 
1525 	/* Make sure that in-place concatenation is used if the LHS is a string. */
1526 	if (opline->extended_value == ZEND_CONCAT && Z_TYPE_P(zptr) == IS_STRING) {
1527 		concat_function(zptr, zptr, value);
1528 		ZEND_ASSERT(Z_TYPE_P(zptr) == IS_STRING && "Concat should return string");
1529 		return;
1530 	}
1531 
1532 	zend_binary_op(&z_copy, zptr, value OPLINE_CC);
1533 	if (EXPECTED(zend_verify_property_type(prop_info, &z_copy, EX_USES_STRICT_TYPES()))) {
1534 		zval_ptr_dtor(zptr);
1535 		ZVAL_COPY_VALUE(zptr, &z_copy);
1536 	} else {
1537 		zval_ptr_dtor(&z_copy);
1538 	}
1539 }
1540 
zend_check_string_offset(zval * dim,int type EXECUTE_DATA_DC)1541 static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type EXECUTE_DATA_DC)
1542 {
1543 	zend_long offset;
1544 
1545 try_again:
1546 	switch(Z_TYPE_P(dim)) {
1547 		case IS_LONG:
1548 			return Z_LVAL_P(dim);
1549 		case IS_STRING:
1550 		{
1551 			bool trailing_data = false;
1552 			/* For BC reasons we allow errors so that we can warn on leading numeric string */
1553 			if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL,
1554 					/* allow errors */ true, NULL, &trailing_data)) {
1555 				if (UNEXPECTED(trailing_data) && type != BP_VAR_UNSET) {
1556 					zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
1557 				}
1558 				return offset;
1559 			}
1560 			zend_illegal_string_offset(dim);
1561 			return 0;
1562 		}
1563 		case IS_UNDEF:
1564 			ZVAL_UNDEFINED_OP2();
1565 			ZEND_FALLTHROUGH;
1566 		case IS_DOUBLE:
1567 		case IS_NULL:
1568 		case IS_FALSE:
1569 		case IS_TRUE:
1570 			zend_error(E_WARNING, "String offset cast occurred");
1571 			break;
1572 		case IS_REFERENCE:
1573 			dim = Z_REFVAL_P(dim);
1574 			goto try_again;
1575 		default:
1576 			zend_illegal_string_offset(dim);
1577 			return 0;
1578 	}
1579 
1580 	return zval_get_long_func(dim, /* is_strict */ false);
1581 }
1582 
zend_wrong_string_offset_error(void)1583 ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void)
1584 {
1585 	const char *msg = NULL;
1586 	const zend_execute_data *execute_data = EG(current_execute_data);
1587 	const zend_op *opline = execute_data->opline;
1588 
1589 	if (UNEXPECTED(EG(exception) != NULL)) {
1590 		return;
1591 	}
1592 
1593 	switch (opline->opcode) {
1594 		case ZEND_ASSIGN_DIM_OP:
1595 			msg = "Cannot use assign-op operators with string offsets";
1596 			break;
1597 		case ZEND_FETCH_LIST_W:
1598 			msg = "Cannot create references to/from string offsets";
1599 			break;
1600 		case ZEND_FETCH_DIM_W:
1601 		case ZEND_FETCH_DIM_RW:
1602 		case ZEND_FETCH_DIM_FUNC_ARG:
1603 		case ZEND_FETCH_DIM_UNSET:
1604 			switch (opline->extended_value) {
1605 				case ZEND_FETCH_DIM_REF:
1606 					msg = "Cannot create references to/from string offsets";
1607 					break;
1608 				case ZEND_FETCH_DIM_DIM:
1609 					msg = "Cannot use string offset as an array";
1610 					break;
1611 				case ZEND_FETCH_DIM_OBJ:
1612 					msg = "Cannot use string offset as an object";
1613 					break;
1614 				case ZEND_FETCH_DIM_INCDEC:
1615 					msg = "Cannot increment/decrement string offsets";
1616 					break;
1617 				EMPTY_SWITCH_DEFAULT_CASE();
1618 			}
1619 			break;
1620 		EMPTY_SWITCH_DEFAULT_CASE();
1621 	}
1622 	ZEND_ASSERT(msg != NULL);
1623 	zend_throw_error(NULL, "%s", msg);
1624 }
1625 
zend_deprecated_function(const zend_function * fbc)1626 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
1627 {
1628 	if (fbc->common.scope) {
1629 		zend_error(E_DEPRECATED, "Method %s::%s() is deprecated",
1630 			ZSTR_VAL(fbc->common.scope->name),
1631 			ZSTR_VAL(fbc->common.function_name)
1632 		);
1633 	} else {
1634 		zend_error(E_DEPRECATED, "Function %s() is deprecated", ZSTR_VAL(fbc->common.function_name));
1635 	}
1636 }
1637 
zend_false_to_array_deprecated(void)1638 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void)
1639 {
1640 	zend_error(E_DEPRECATED, "Automatic conversion of false to array is deprecated");
1641 }
1642 
zend_assign_to_string_offset(zval * str,zval * dim,zval * value OPLINE_DC EXECUTE_DATA_DC)1643 static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC)
1644 {
1645 	zend_uchar c;
1646 	size_t string_len;
1647 	zend_long offset;
1648 	zend_string *s;
1649 
1650 	/* separate string */
1651 	if (Z_REFCOUNTED_P(str) && Z_REFCOUNT_P(str) == 1) {
1652 		s = Z_STR_P(str);
1653 	} else {
1654 		s = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
1655 		ZSTR_H(s) = ZSTR_H(Z_STR_P(str));
1656 		if (Z_REFCOUNTED_P(str)) {
1657 			GC_DELREF(Z_STR_P(str));
1658 		}
1659 		ZVAL_NEW_STR(str, s);
1660 	}
1661 
1662 	if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
1663 		offset = Z_LVAL_P(dim);
1664 	} else {
1665 		/* The string may be destroyed while throwing the notice.
1666 		 * Temporarily increase the refcount to detect this situation. */
1667 		GC_ADDREF(s);
1668 		offset = zend_check_string_offset(dim, BP_VAR_W EXECUTE_DATA_CC);
1669 		if (UNEXPECTED(GC_DELREF(s) == 0)) {
1670 			zend_string_efree(s);
1671 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1672 				ZVAL_NULL(EX_VAR(opline->result.var));
1673 			}
1674 			return;
1675 		}
1676 		/* Illegal offset assignment */
1677 		if (UNEXPECTED(EG(exception) != NULL)) {
1678 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1679 				ZVAL_UNDEF(EX_VAR(opline->result.var));
1680 			}
1681 			return;
1682 		}
1683 	}
1684 
1685 	if (UNEXPECTED(offset < -(zend_long)ZSTR_LEN(s))) {
1686 		/* Error on negative offset */
1687 		zend_error(E_WARNING, "Illegal string offset " ZEND_LONG_FMT, offset);
1688 		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1689 			ZVAL_NULL(EX_VAR(opline->result.var));
1690 		}
1691 		return;
1692 	}
1693 
1694 	if (offset < 0) { /* Handle negative offset */
1695 		offset += (zend_long)ZSTR_LEN(s);
1696 	}
1697 
1698 	if (UNEXPECTED(Z_TYPE_P(value) != IS_STRING)) {
1699 		zend_string *tmp;
1700 
1701 		/* The string may be destroyed while throwing the notice.
1702 		 * Temporarily increase the refcount to detect this situation. */
1703 		GC_ADDREF(s);
1704 		if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1705 			zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC);
1706 		}
1707 		/* Convert to string, just the time to pick the 1st byte */
1708 		tmp = zval_try_get_string_func(value);
1709 		if (UNEXPECTED(GC_DELREF(s) == 0)) {
1710 			zend_string_efree(s);
1711 			if (tmp) {
1712 				zend_string_release_ex(tmp, 0);
1713 			}
1714 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1715 				ZVAL_NULL(EX_VAR(opline->result.var));
1716 			}
1717 			return;
1718 		}
1719 		if (UNEXPECTED(!tmp)) {
1720 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1721 				ZVAL_UNDEF(EX_VAR(opline->result.var));
1722 			}
1723 			return;
1724 		}
1725 
1726 		string_len = ZSTR_LEN(tmp);
1727 		c = (zend_uchar)ZSTR_VAL(tmp)[0];
1728 		zend_string_release_ex(tmp, 0);
1729 	} else {
1730 		string_len = Z_STRLEN_P(value);
1731 		c = (zend_uchar)Z_STRVAL_P(value)[0];
1732 	}
1733 
1734 	if (UNEXPECTED(string_len != 1)) {
1735 		if (string_len == 0) {
1736 			/* Error on empty input string */
1737 			zend_throw_error(NULL, "Cannot assign an empty string to a string offset");
1738 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1739 				ZVAL_NULL(EX_VAR(opline->result.var));
1740 			}
1741 			return;
1742 		}
1743 
1744 		/* The string may be destroyed while throwing the notice.
1745 		 * Temporarily increase the refcount to detect this situation. */
1746 		GC_ADDREF(s);
1747 		zend_error(E_WARNING, "Only the first byte will be assigned to the string offset");
1748 		if (UNEXPECTED(GC_DELREF(s) == 0)) {
1749 			zend_string_efree(s);
1750 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1751 				ZVAL_NULL(EX_VAR(opline->result.var));
1752 			}
1753 			return;
1754 		}
1755 		/* Illegal offset assignment */
1756 		if (UNEXPECTED(EG(exception) != NULL)) {
1757 			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1758 				ZVAL_UNDEF(EX_VAR(opline->result.var));
1759 			}
1760 			return;
1761 		}
1762 	}
1763 
1764 	if ((size_t)offset >= ZSTR_LEN(s)) {
1765 		/* Extend string if needed */
1766 		zend_long old_len = ZSTR_LEN(s);
1767 		ZVAL_NEW_STR(str, zend_string_extend(s, (size_t)offset + 1, 0));
1768 		memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
1769 		Z_STRVAL_P(str)[offset+1] = 0;
1770 	} else {
1771 		zend_string_forget_hash_val(Z_STR_P(str));
1772 	}
1773 
1774 	Z_STRVAL_P(str)[offset] = c;
1775 
1776 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1777 		/* Return the new character */
1778 		ZVAL_CHAR(EX_VAR(opline->result.var), c);
1779 	}
1780 }
1781 
zend_get_prop_not_accepting_double(zend_reference * ref)1782 static zend_property_info *zend_get_prop_not_accepting_double(zend_reference *ref)
1783 {
1784 	zend_property_info *prop;
1785 	ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
1786 		if (!(ZEND_TYPE_FULL_MASK(prop->type) & MAY_BE_DOUBLE)) {
1787 			return prop;
1788 		}
1789 	} ZEND_REF_FOREACH_TYPE_SOURCES_END();
1790 	return NULL;
1791 }
1792 
zend_throw_incdec_ref_error(zend_reference * ref,zend_property_info * error_prop OPLINE_DC)1793 static ZEND_COLD zend_long zend_throw_incdec_ref_error(
1794 		zend_reference *ref, zend_property_info *error_prop OPLINE_DC)
1795 {
1796 	zend_string *type_str = zend_type_to_string(error_prop->type);
1797 	if (ZEND_IS_INCREMENT(opline->opcode)) {
1798 		zend_type_error(
1799 			"Cannot increment a reference held by property %s::$%s of type %s past its maximal value",
1800 			ZSTR_VAL(error_prop->ce->name),
1801 			zend_get_unmangled_property_name(error_prop->name),
1802 			ZSTR_VAL(type_str));
1803 		zend_string_release(type_str);
1804 		return ZEND_LONG_MAX;
1805 	} else {
1806 		zend_type_error(
1807 			"Cannot decrement a reference held by property %s::$%s of type %s past its minimal value",
1808 			ZSTR_VAL(error_prop->ce->name),
1809 			zend_get_unmangled_property_name(error_prop->name),
1810 			ZSTR_VAL(type_str));
1811 		zend_string_release(type_str);
1812 		return ZEND_LONG_MIN;
1813 	}
1814 }
1815 
zend_throw_incdec_prop_error(zend_property_info * prop OPLINE_DC)1816 static ZEND_COLD zend_long zend_throw_incdec_prop_error(zend_property_info *prop OPLINE_DC) {
1817 	zend_string *type_str = zend_type_to_string(prop->type);
1818 	if (ZEND_IS_INCREMENT(opline->opcode)) {
1819 		zend_type_error("Cannot increment property %s::$%s of type %s past its maximal value",
1820 			ZSTR_VAL(prop->ce->name),
1821 			zend_get_unmangled_property_name(prop->name),
1822 			ZSTR_VAL(type_str));
1823 		zend_string_release(type_str);
1824 		return ZEND_LONG_MAX;
1825 	} else {
1826 		zend_type_error("Cannot decrement property %s::$%s of type %s past its minimal value",
1827 			ZSTR_VAL(prop->ce->name),
1828 			zend_get_unmangled_property_name(prop->name),
1829 			ZSTR_VAL(type_str));
1830 		zend_string_release(type_str);
1831 		return ZEND_LONG_MIN;
1832 	}
1833 }
1834 
zend_incdec_typed_ref(zend_reference * ref,zval * copy OPLINE_DC EXECUTE_DATA_DC)1835 static void zend_incdec_typed_ref(zend_reference *ref, zval *copy OPLINE_DC EXECUTE_DATA_DC)
1836 {
1837 	zval tmp;
1838 	zval *var_ptr = &ref->val;
1839 
1840 	if (!copy) {
1841 		copy = &tmp;
1842 	}
1843 
1844 	ZVAL_COPY(copy, var_ptr);
1845 
1846 	if (ZEND_IS_INCREMENT(opline->opcode)) {
1847 		increment_function(var_ptr);
1848 	} else {
1849 		decrement_function(var_ptr);
1850 	}
1851 
1852 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(copy) == IS_LONG) {
1853 		zend_property_info *error_prop = zend_get_prop_not_accepting_double(ref);
1854 		if (UNEXPECTED(error_prop)) {
1855 			zend_long val = zend_throw_incdec_ref_error(ref, error_prop OPLINE_CC);
1856 			ZVAL_LONG(var_ptr, val);
1857 		}
1858 	} else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, EX_USES_STRICT_TYPES()))) {
1859 		zval_ptr_dtor(var_ptr);
1860 		ZVAL_COPY_VALUE(var_ptr, copy);
1861 		ZVAL_UNDEF(copy);
1862 	} else if (copy == &tmp) {
1863 		zval_ptr_dtor(&tmp);
1864 	}
1865 }
1866 
zend_incdec_typed_prop(zend_property_info * prop_info,zval * var_ptr,zval * copy OPLINE_DC EXECUTE_DATA_DC)1867 static void zend_incdec_typed_prop(zend_property_info *prop_info, zval *var_ptr, zval *copy OPLINE_DC EXECUTE_DATA_DC)
1868 {
1869 	zval tmp;
1870 
1871 	if (!copy) {
1872 		copy = &tmp;
1873 	}
1874 
1875 	ZVAL_COPY(copy, var_ptr);
1876 
1877 	if (ZEND_IS_INCREMENT(opline->opcode)) {
1878 		increment_function(var_ptr);
1879 	} else {
1880 		decrement_function(var_ptr);
1881 	}
1882 
1883 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(copy) == IS_LONG) {
1884 		if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
1885 			zend_long val = zend_throw_incdec_prop_error(prop_info OPLINE_CC);
1886 			ZVAL_LONG(var_ptr, val);
1887 		}
1888 	} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
1889 		zval_ptr_dtor(var_ptr);
1890 		ZVAL_COPY_VALUE(var_ptr, copy);
1891 		ZVAL_UNDEF(copy);
1892 	} else if (copy == &tmp) {
1893 		zval_ptr_dtor(&tmp);
1894 	}
1895 }
1896 
zend_pre_incdec_property_zval(zval * prop,zend_property_info * prop_info OPLINE_DC EXECUTE_DATA_DC)1897 static void zend_pre_incdec_property_zval(zval *prop, zend_property_info *prop_info OPLINE_DC EXECUTE_DATA_DC)
1898 {
1899 	if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
1900 		if (ZEND_IS_INCREMENT(opline->opcode)) {
1901 			fast_long_increment_function(prop);
1902 		} else {
1903 			fast_long_decrement_function(prop);
1904 		}
1905 		if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
1906 				&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
1907 			zend_long val = zend_throw_incdec_prop_error(prop_info OPLINE_CC);
1908 			ZVAL_LONG(prop, val);
1909 		}
1910 	} else {
1911 		do {
1912 			if (Z_ISREF_P(prop)) {
1913 				zend_reference *ref = Z_REF_P(prop);
1914 				prop = Z_REFVAL_P(prop);
1915 				if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
1916 					zend_incdec_typed_ref(ref, NULL OPLINE_CC EXECUTE_DATA_CC);
1917 					break;
1918 				}
1919 			}
1920 
1921 			if (UNEXPECTED(prop_info)) {
1922 				zend_incdec_typed_prop(prop_info, prop, NULL OPLINE_CC EXECUTE_DATA_CC);
1923 			} else if (ZEND_IS_INCREMENT(opline->opcode)) {
1924 				increment_function(prop);
1925 			} else {
1926 				decrement_function(prop);
1927 			}
1928 		} while (0);
1929 	}
1930 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1931 		ZVAL_COPY(EX_VAR(opline->result.var), prop);
1932 	}
1933 }
1934 
zend_post_incdec_property_zval(zval * prop,zend_property_info * prop_info OPLINE_DC EXECUTE_DATA_DC)1935 static void zend_post_incdec_property_zval(zval *prop, zend_property_info *prop_info OPLINE_DC EXECUTE_DATA_DC)
1936 {
1937 	if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
1938 		ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(prop));
1939 		if (ZEND_IS_INCREMENT(opline->opcode)) {
1940 			fast_long_increment_function(prop);
1941 		} else {
1942 			fast_long_decrement_function(prop);
1943 		}
1944 		if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
1945 				&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
1946 			zend_long val = zend_throw_incdec_prop_error(prop_info OPLINE_CC);
1947 			ZVAL_LONG(prop, val);
1948 		}
1949 	} else {
1950 		if (Z_ISREF_P(prop)) {
1951 			zend_reference *ref = Z_REF_P(prop);
1952 			prop = Z_REFVAL_P(prop);
1953 			if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
1954 				zend_incdec_typed_ref(ref, EX_VAR(opline->result.var) OPLINE_CC EXECUTE_DATA_CC);
1955 				return;
1956 			}
1957 		}
1958 
1959 		if (UNEXPECTED(prop_info)) {
1960 			zend_incdec_typed_prop(prop_info, prop, EX_VAR(opline->result.var) OPLINE_CC EXECUTE_DATA_CC);
1961 		} else {
1962 			ZVAL_COPY(EX_VAR(opline->result.var), prop);
1963 			if (ZEND_IS_INCREMENT(opline->opcode)) {
1964 				increment_function(prop);
1965 			} else {
1966 				decrement_function(prop);
1967 			}
1968 		}
1969 	}
1970 }
1971 
zend_post_incdec_overloaded_property(zend_object * object,zend_string * name,void ** cache_slot OPLINE_DC EXECUTE_DATA_DC)1972 static zend_never_inline void zend_post_incdec_overloaded_property(zend_object *object, zend_string *name, void **cache_slot OPLINE_DC EXECUTE_DATA_DC)
1973 {
1974 	zval rv;
1975 	zval *z;
1976 	zval z_copy;
1977 
1978 	GC_ADDREF(object);
1979 	z =object->handlers->read_property(object, name, BP_VAR_R, cache_slot, &rv);
1980 	if (UNEXPECTED(EG(exception))) {
1981 		OBJ_RELEASE(object);
1982 		ZVAL_UNDEF(EX_VAR(opline->result.var));
1983 		return;
1984 	}
1985 
1986 	ZVAL_COPY_DEREF(&z_copy, z);
1987 	ZVAL_COPY(EX_VAR(opline->result.var), &z_copy);
1988 	if (ZEND_IS_INCREMENT(opline->opcode)) {
1989 		increment_function(&z_copy);
1990 	} else {
1991 		decrement_function(&z_copy);
1992 	}
1993 	object->handlers->write_property(object, name, &z_copy, cache_slot);
1994 	OBJ_RELEASE(object);
1995 	zval_ptr_dtor(&z_copy);
1996 	if (z == &rv) {
1997 		zval_ptr_dtor(z);
1998 	}
1999 }
2000 
zend_pre_incdec_overloaded_property(zend_object * object,zend_string * name,void ** cache_slot OPLINE_DC EXECUTE_DATA_DC)2001 static zend_never_inline void zend_pre_incdec_overloaded_property(zend_object *object, zend_string *name, void **cache_slot OPLINE_DC EXECUTE_DATA_DC)
2002 {
2003 	zval rv;
2004 	zval *z;
2005 	zval z_copy;
2006 
2007 	GC_ADDREF(object);
2008 	z = object->handlers->read_property(object, name, BP_VAR_R, cache_slot, &rv);
2009 	if (UNEXPECTED(EG(exception))) {
2010 		OBJ_RELEASE(object);
2011 		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2012 			ZVAL_NULL(EX_VAR(opline->result.var));
2013 		}
2014 		return;
2015 	}
2016 
2017 	ZVAL_COPY_DEREF(&z_copy, z);
2018 	if (ZEND_IS_INCREMENT(opline->opcode)) {
2019 		increment_function(&z_copy);
2020 	} else {
2021 		decrement_function(&z_copy);
2022 	}
2023 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2024 		ZVAL_COPY(EX_VAR(opline->result.var), &z_copy);
2025 	}
2026 	object->handlers->write_property(object, name, &z_copy, cache_slot);
2027 	OBJ_RELEASE(object);
2028 	zval_ptr_dtor(&z_copy);
2029 	if (z == &rv) {
2030 		zval_ptr_dtor(z);
2031 	}
2032 }
2033 
zend_assign_op_overloaded_property(zend_object * object,zend_string * name,void ** cache_slot,zval * value OPLINE_DC EXECUTE_DATA_DC)2034 static zend_never_inline void zend_assign_op_overloaded_property(zend_object *object, zend_string *name, void **cache_slot, zval *value OPLINE_DC EXECUTE_DATA_DC)
2035 {
2036 	zval *z;
2037 	zval rv, res;
2038 
2039 	GC_ADDREF(object);
2040 	z = object->handlers->read_property(object, name, BP_VAR_R, cache_slot, &rv);
2041 	if (UNEXPECTED(EG(exception))) {
2042 		OBJ_RELEASE(object);
2043 		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2044 			ZVAL_UNDEF(EX_VAR(opline->result.var));
2045 		}
2046 		return;
2047 	}
2048 	if (zend_binary_op(&res, z, value OPLINE_CC) == SUCCESS) {
2049 		object->handlers->write_property(object, name, &res, cache_slot);
2050 	}
2051 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2052 		ZVAL_COPY(EX_VAR(opline->result.var), &res);
2053 	}
2054 	if (z == &rv) {
2055 		zval_ptr_dtor(z);
2056 	}
2057 	zval_ptr_dtor(&res);
2058 	OBJ_RELEASE(object);
2059 }
2060 
2061 /* Utility Functions for Extensions */
zend_extension_statement_handler(const zend_extension * extension,zend_execute_data * frame)2062 static void zend_extension_statement_handler(const zend_extension *extension, zend_execute_data *frame)
2063 {
2064 	if (extension->statement_handler) {
2065 		extension->statement_handler(frame);
2066 	}
2067 }
2068 
2069 
zend_extension_fcall_begin_handler(const zend_extension * extension,zend_execute_data * frame)2070 static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_execute_data *frame)
2071 {
2072 	if (extension->fcall_begin_handler) {
2073 		extension->fcall_begin_handler(frame);
2074 	}
2075 }
2076 
2077 
zend_extension_fcall_end_handler(const zend_extension * extension,zend_execute_data * frame)2078 static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_execute_data *frame)
2079 {
2080 	if (extension->fcall_end_handler) {
2081 		extension->fcall_end_handler(frame);
2082 	}
2083 }
2084 
2085 
zend_get_target_symbol_table(int fetch_type EXECUTE_DATA_DC)2086 static zend_always_inline HashTable *zend_get_target_symbol_table(int fetch_type EXECUTE_DATA_DC)
2087 {
2088 	HashTable *ht;
2089 
2090 	if (EXPECTED(fetch_type & (ZEND_FETCH_GLOBAL_LOCK | ZEND_FETCH_GLOBAL))) {
2091 		ht = &EG(symbol_table);
2092 	} else {
2093 		ZEND_ASSERT(fetch_type & ZEND_FETCH_LOCAL);
2094 		if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
2095 			zend_rebuild_symbol_table();
2096 		}
2097 		ht = EX(symbol_table);
2098 	}
2099 	return ht;
2100 }
2101 
zend_undefined_offset(zend_long lval)2102 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_offset(zend_long lval)
2103 {
2104 	zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, lval);
2105 }
2106 
zend_undefined_index(const zend_string * offset)2107 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_index(const zend_string *offset)
2108 {
2109 	zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset));
2110 }
2111 
zend_undefined_offset_write(HashTable * ht,zend_long lval)2112 ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_offset_write(HashTable *ht, zend_long lval)
2113 {
2114 	/* The array may be destroyed while throwing the notice.
2115 	 * Temporarily increase the refcount to detect this situation. */
2116 	if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2117 		GC_ADDREF(ht);
2118 	}
2119 	zend_undefined_offset(lval);
2120 	if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
2121 		if (!GC_REFCOUNT(ht)) {
2122 			zend_array_destroy(ht);
2123 		}
2124 		return NULL;
2125 	}
2126 	if (EG(exception)) {
2127 		return NULL;
2128 	}
2129 	return zend_hash_index_add_new(ht, lval, &EG(uninitialized_zval));
2130 }
2131 
zend_undefined_index_write(HashTable * ht,zend_string * offset)2132 ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_index_write(HashTable *ht, zend_string *offset)
2133 {
2134 	zval *retval;
2135 
2136 	/* The array may be destroyed while throwing the notice.
2137 	 * Temporarily increase the refcount to detect this situation. */
2138 	if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2139 		GC_ADDREF(ht);
2140 	}
2141 	/* Key may be released while throwing the undefined index warning. */
2142 	zend_string_addref(offset);
2143 	zend_undefined_index(offset);
2144 	if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
2145 		if (!GC_REFCOUNT(ht)) {
2146 			zend_array_destroy(ht);
2147 		}
2148 		retval = NULL;
2149 	} else if (EG(exception)) {
2150 		retval = NULL;
2151 	} else {
2152 		retval = zend_hash_add_new(ht, offset, &EG(uninitialized_zval));
2153 	}
2154 	zend_string_release(offset);
2155 	return retval;
2156 }
2157 
zend_undefined_method(const zend_class_entry * ce,const zend_string * method)2158 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(const zend_class_entry *ce, const zend_string *method)
2159 {
2160 	zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(method));
2161 }
2162 
zend_invalid_method_call(zval * object,zval * function_name)2163 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call(zval *object, zval *function_name)
2164 {
2165 	zend_throw_error(NULL, "Call to a member function %s() on %s",
2166 		Z_STRVAL_P(function_name), zend_zval_type_name(object));
2167 }
2168 
zend_non_static_method_call(const zend_function * fbc)2169 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc)
2170 {
2171 	zend_throw_error(
2172 		zend_ce_error,
2173 		"Non-static method %s::%s() cannot be called statically",
2174 		ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
2175 }
2176 
zend_param_must_be_ref(const zend_function * func,uint32_t arg_num)2177 ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num)
2178 {
2179 	const char *arg_name = get_function_arg_name(func, arg_num);
2180 
2181 	zend_error(E_WARNING, "%s%s%s(): Argument #%d%s%s%s must be passed by reference, value given",
2182 		func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
2183 		func->common.scope ? "::" : "",
2184 		ZSTR_VAL(func->common.function_name),
2185 		arg_num,
2186 		arg_name ? " ($" : "",
2187 		arg_name ? arg_name : "",
2188 		arg_name ? ")" : ""
2189 	);
2190 }
2191 
zend_use_scalar_as_array(void)2192 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_scalar_as_array(void)
2193 {
2194 	zend_throw_error(NULL, "Cannot use a scalar value as an array");
2195 }
2196 
zend_cannot_add_element(void)2197 ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void)
2198 {
2199 	zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
2200 }
2201 
zend_use_resource_as_offset(const zval * dim)2202 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim)
2203 {
2204 	zend_error(E_WARNING,
2205 		"Resource ID#" ZEND_LONG_FMT " used as offset, casting to integer (" ZEND_LONG_FMT ")",
2206 		Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
2207 }
2208 
zend_use_new_element_for_string(void)2209 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_string(void)
2210 {
2211 	zend_throw_error(NULL, "[] operator not supported for strings");
2212 }
2213 
zend_binary_assign_op_dim_slow(zval * container,zval * dim OPLINE_DC EXECUTE_DATA_DC)2214 static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC)
2215 {
2216 	if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
2217 		if (opline->op2_type == IS_UNUSED) {
2218 			zend_use_new_element_for_string();
2219 		} else {
2220 			zend_check_string_offset(dim, BP_VAR_RW EXECUTE_DATA_CC);
2221 			zend_wrong_string_offset_error();
2222 		}
2223 	} else {
2224 		zend_use_scalar_as_array();
2225 	}
2226 }
2227 
slow_index_convert(HashTable * ht,const zval * dim,zend_value * value EXECUTE_DATA_DC)2228 static zend_never_inline zend_uchar slow_index_convert(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC)
2229 {
2230 	switch (Z_TYPE_P(dim)) {
2231 		case IS_UNDEF: {
2232 			/* The array may be destroyed while throwing the notice.
2233 			 * Temporarily increase the refcount to detect this situation. */
2234 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2235 				GC_ADDREF(ht);
2236 			}
2237 			ZVAL_UNDEFINED_OP2();
2238 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
2239 				zend_array_destroy(ht);
2240 				return IS_NULL;
2241 			}
2242 			if (EG(exception)) {
2243 				return IS_NULL;
2244 			}
2245 			ZEND_FALLTHROUGH;
2246 		}
2247 		case IS_NULL:
2248 			value->str = ZSTR_EMPTY_ALLOC();
2249 			return IS_STRING;
2250 		case IS_DOUBLE:
2251 			value->lval = zend_dval_to_lval(Z_DVAL_P(dim));
2252 			if (!zend_is_long_compatible(Z_DVAL_P(dim), value->lval)) {
2253 				/* The array may be destroyed while throwing the notice.
2254 				 * Temporarily increase the refcount to detect this situation. */
2255 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2256 					GC_ADDREF(ht);
2257 				}
2258 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
2259 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
2260 					zend_array_destroy(ht);
2261 					return IS_NULL;
2262 				}
2263 				if (EG(exception)) {
2264 					return IS_NULL;
2265 				}
2266 			}
2267 			return IS_LONG;
2268 		case IS_RESOURCE:
2269 			/* The array may be destroyed while throwing the notice.
2270 			 * Temporarily increase the refcount to detect this situation. */
2271 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2272 				GC_ADDREF(ht);
2273 			}
2274 			zend_use_resource_as_offset(dim);
2275 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
2276 				zend_array_destroy(ht);
2277 				return IS_NULL;
2278 			}
2279 			if (EG(exception)) {
2280 				return IS_NULL;
2281 			}
2282 			value->lval = Z_RES_HANDLE_P(dim);
2283 			return IS_LONG;
2284 		case IS_FALSE:
2285 			value->lval = 0;
2286 			return IS_LONG;
2287 		case IS_TRUE:
2288 			value->lval = 1;
2289 			return IS_LONG;
2290 		default:
2291 			zend_illegal_offset();
2292 			return IS_NULL;
2293 	}
2294 }
2295 
slow_index_convert_w(HashTable * ht,const zval * dim,zend_value * value EXECUTE_DATA_DC)2296 static zend_never_inline zend_uchar slow_index_convert_w(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC)
2297 {
2298 	switch (Z_TYPE_P(dim)) {
2299 		case IS_UNDEF: {
2300 			/* The array may be destroyed while throwing the notice.
2301 			 * Temporarily increase the refcount to detect this situation. */
2302 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2303 				GC_ADDREF(ht);
2304 			}
2305 			ZVAL_UNDEFINED_OP2();
2306 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
2307 				if (!GC_REFCOUNT(ht)) {
2308 					zend_array_destroy(ht);
2309 				}
2310 				return IS_NULL;
2311 			}
2312 			if (EG(exception)) {
2313 				return IS_NULL;
2314 			}
2315 			ZEND_FALLTHROUGH;
2316 		}
2317 		case IS_NULL:
2318 			value->str = ZSTR_EMPTY_ALLOC();
2319 			return IS_STRING;
2320 		case IS_DOUBLE:
2321 			value->lval = zend_dval_to_lval(Z_DVAL_P(dim));
2322 			if (!zend_is_long_compatible(Z_DVAL_P(dim), value->lval)) {
2323 				/* The array may be destroyed while throwing the notice.
2324 				 * Temporarily increase the refcount to detect this situation. */
2325 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2326 					GC_ADDREF(ht);
2327 				}
2328 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
2329 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
2330 					if (!GC_REFCOUNT(ht)) {
2331 						zend_array_destroy(ht);
2332 					}
2333 					return IS_NULL;
2334 				}
2335 				if (EG(exception)) {
2336 					return IS_NULL;
2337 				}
2338 			}
2339 			return IS_LONG;
2340 		case IS_RESOURCE:
2341 			/* The array may be destroyed while throwing the notice.
2342 			 * Temporarily increase the refcount to detect this situation. */
2343 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2344 				GC_ADDREF(ht);
2345 			}
2346 			zend_use_resource_as_offset(dim);
2347 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
2348 				if (!GC_REFCOUNT(ht)) {
2349 					zend_array_destroy(ht);
2350 				}
2351 				return IS_NULL;
2352 			}
2353 			if (EG(exception)) {
2354 				return IS_NULL;
2355 			}
2356 			value->lval = Z_RES_HANDLE_P(dim);
2357 			return IS_LONG;
2358 		case IS_FALSE:
2359 			value->lval = 0;
2360 			return IS_LONG;
2361 		case IS_TRUE:
2362 			value->lval = 1;
2363 			return IS_LONG;
2364 		default:
2365 			zend_illegal_offset();
2366 			return IS_NULL;
2367 	}
2368 }
2369 
zend_fetch_dimension_address_inner(HashTable * ht,const zval * dim,int dim_type,int type EXECUTE_DATA_DC)2370 static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type EXECUTE_DATA_DC)
2371 {
2372 	zval *retval = NULL;
2373 	zend_string *offset_key;
2374 	zend_ulong hval;
2375 
2376 try_again:
2377 	if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
2378 		hval = Z_LVAL_P(dim);
2379 num_index:
2380 		if (type != BP_VAR_W) {
2381 			ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
2382 			return retval;
2383 num_undef:
2384 			switch (type) {
2385 				case BP_VAR_R:
2386 					zend_undefined_offset(hval);
2387 					ZEND_FALLTHROUGH;
2388 				case BP_VAR_UNSET:
2389 				case BP_VAR_IS:
2390 					retval = &EG(uninitialized_zval);
2391 					break;
2392 				case BP_VAR_RW:
2393 					retval = zend_undefined_offset_write(ht, hval);
2394 					break;
2395 				}
2396 		} else {
2397 			ZEND_HASH_INDEX_LOOKUP(ht, hval, retval);
2398 		}
2399 	} else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
2400 		offset_key = Z_STR_P(dim);
2401 		if (ZEND_CONST_COND(dim_type != IS_CONST, 1)) {
2402 			if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
2403 				goto num_index;
2404 			}
2405 		}
2406 str_index:
2407 		if (type != BP_VAR_W) {
2408 			retval = zend_hash_find_ex(ht, offset_key, ZEND_CONST_COND(dim_type == IS_CONST, 0));
2409 			if (!retval) {
2410 				switch (type) {
2411 					case BP_VAR_R:
2412 						zend_undefined_index(offset_key);
2413 						ZEND_FALLTHROUGH;
2414 					case BP_VAR_UNSET:
2415 					case BP_VAR_IS:
2416 						retval = &EG(uninitialized_zval);
2417 						break;
2418 					case BP_VAR_RW:
2419 						retval = zend_undefined_index_write(ht, offset_key);
2420 						break;
2421 				}
2422 			}
2423 		} else {
2424 			retval = zend_hash_lookup(ht, offset_key);
2425 		}
2426 	} else if (EXPECTED(Z_TYPE_P(dim) == IS_REFERENCE)) {
2427 		dim = Z_REFVAL_P(dim);
2428 		goto try_again;
2429 	} else {
2430 		zend_value val;
2431 		zend_uchar t;
2432 
2433 		if (type != BP_VAR_W && type != BP_VAR_RW) {
2434 			t = slow_index_convert(ht, dim, &val EXECUTE_DATA_CC);
2435 		} else {
2436 			t = slow_index_convert_w(ht, dim, &val EXECUTE_DATA_CC);
2437 		}
2438 		if (t == IS_STRING) {
2439 			offset_key = val.str;
2440 			goto str_index;
2441 		} else if (t == IS_LONG) {
2442 			hval = val.lval;
2443 			goto num_index;
2444 		} else {
2445 			retval = (type == BP_VAR_W || type == BP_VAR_RW) ?
2446 					NULL : &EG(uninitialized_zval);
2447 		}
2448 	}
2449 	return retval;
2450 }
2451 
zend_fetch_dimension_address_inner_W(HashTable * ht,const zval * dim EXECUTE_DATA_DC)2452 static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_W(HashTable *ht, const zval *dim EXECUTE_DATA_DC)
2453 {
2454 	return zend_fetch_dimension_address_inner(ht, dim, IS_TMP_VAR, BP_VAR_W EXECUTE_DATA_CC);
2455 }
2456 
zend_fetch_dimension_address_inner_W_CONST(HashTable * ht,const zval * dim EXECUTE_DATA_DC)2457 static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_W_CONST(HashTable *ht, const zval *dim EXECUTE_DATA_DC)
2458 {
2459 	return zend_fetch_dimension_address_inner(ht, dim, IS_CONST, BP_VAR_W EXECUTE_DATA_CC);
2460 }
2461 
zend_fetch_dimension_address_inner_RW(HashTable * ht,const zval * dim EXECUTE_DATA_DC)2462 static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_RW(HashTable *ht, const zval *dim EXECUTE_DATA_DC)
2463 {
2464 	return zend_fetch_dimension_address_inner(ht, dim, IS_TMP_VAR, BP_VAR_RW EXECUTE_DATA_CC);
2465 }
2466 
zend_fetch_dimension_address_inner_RW_CONST(HashTable * ht,const zval * dim EXECUTE_DATA_DC)2467 static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_RW_CONST(HashTable *ht, const zval *dim EXECUTE_DATA_DC)
2468 {
2469 	return zend_fetch_dimension_address_inner(ht, dim, IS_CONST, BP_VAR_RW EXECUTE_DATA_CC);
2470 }
2471 
zend_fetch_dimension_address(zval * result,zval * container,zval * dim,int dim_type,int type EXECUTE_DATA_DC)2472 static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type EXECUTE_DATA_DC)
2473 {
2474 	zval *retval;
2475 
2476 	if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
2477 try_array:
2478 		SEPARATE_ARRAY(container);
2479 fetch_from_array:
2480 		if (dim == NULL) {
2481 			retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
2482 			if (UNEXPECTED(retval == NULL)) {
2483 				zend_cannot_add_element();
2484 				ZVAL_UNDEF(result);
2485 				return;
2486 			}
2487 		} else {
2488 			retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type EXECUTE_DATA_CC);
2489 			if (UNEXPECTED(!retval)) {
2490 				/* This may fail without throwing if the array was modified while throwing an
2491 				 * undefined index error. */
2492 				ZVAL_NULL(result);
2493 				return;
2494 			}
2495 		}
2496 		ZVAL_INDIRECT(result, retval);
2497 		return;
2498 	} else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
2499 		zend_reference *ref = Z_REF_P(container);
2500 		container = Z_REFVAL_P(container);
2501 		if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
2502 			goto try_array;
2503 		} else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
2504 			if (type != BP_VAR_UNSET) {
2505 				if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
2506 					if (UNEXPECTED(!zend_verify_ref_array_assignable(ref))) {
2507 						ZVAL_UNDEF(result);
2508 						return;
2509 					}
2510 				}
2511 				array_init(container);
2512 				goto fetch_from_array;
2513 			} else {
2514 				goto return_null;
2515 			}
2516 		}
2517 	}
2518 	if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
2519 		if (dim == NULL) {
2520 			zend_use_new_element_for_string();
2521 		} else {
2522 			zend_check_string_offset(dim, type EXECUTE_DATA_CC);
2523 			zend_wrong_string_offset_error();
2524 		}
2525 		ZVAL_UNDEF(result);
2526 	} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
2527 		zend_object *obj = Z_OBJ_P(container);
2528 		GC_ADDREF(obj);
2529 		if (ZEND_CONST_COND(dim_type == IS_CV, dim != NULL) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
2530 			dim = ZVAL_UNDEFINED_OP2();
2531 		} else if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
2532 			dim++;
2533 		}
2534 		retval = obj->handlers->read_dimension(obj, dim, type, result);
2535 
2536 		if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
2537 			zend_class_entry *ce = obj->ce;
2538 
2539 			ZVAL_NULL(result);
2540 			zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
2541 		} else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) {
2542 			if (!Z_ISREF_P(retval)) {
2543 				if (result != retval) {
2544 					ZVAL_COPY(result, retval);
2545 					retval = result;
2546 				}
2547 				if (Z_TYPE_P(retval) != IS_OBJECT) {
2548 					zend_class_entry *ce = obj->ce;
2549 					zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
2550 				}
2551 			} else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) {
2552 				ZVAL_UNREF(retval);
2553 			}
2554 			if (result != retval) {
2555 				ZVAL_INDIRECT(result, retval);
2556 			}
2557 		} else {
2558 			ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
2559 			ZVAL_UNDEF(result);
2560 		}
2561 		if (UNEXPECTED(GC_DELREF(obj) == 0)) {
2562 			zend_objects_store_del(obj);
2563 		}
2564 	} else {
2565 		if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
2566 			if (type != BP_VAR_W && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
2567 				ZVAL_UNDEFINED_OP1();
2568 			}
2569 			if (type != BP_VAR_UNSET) {
2570 				HashTable *ht = zend_new_array(0);
2571 				zend_uchar old_type = Z_TYPE_P(container);
2572 
2573 				ZVAL_ARR(container, ht);
2574 				if (UNEXPECTED(old_type == IS_FALSE)) {
2575 					GC_ADDREF(ht);
2576 					zend_false_to_array_deprecated();
2577 					if (UNEXPECTED(GC_DELREF(ht) == 0)) {
2578 						zend_array_destroy(ht);
2579 						goto return_null;
2580 					}
2581 				}
2582 				goto fetch_from_array;
2583 			} else {
2584 				if (UNEXPECTED(Z_TYPE_P(container) == IS_FALSE)) {
2585 					zend_false_to_array_deprecated();
2586 				}
2587 return_null:
2588 				/* for read-mode only */
2589 				if (ZEND_CONST_COND(dim_type == IS_CV, dim != NULL) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
2590 					ZVAL_UNDEFINED_OP2();
2591 				}
2592 				ZVAL_NULL(result);
2593 			}
2594 		} else {
2595 			if (type == BP_VAR_UNSET) {
2596 				zend_throw_error(NULL, "Cannot unset offset in a non-array variable");
2597 				ZVAL_UNDEF(result);
2598 			} else {
2599 				zend_use_scalar_as_array();
2600 				ZVAL_UNDEF(result);
2601 			}
2602 		}
2603 	}
2604 }
2605 
zend_fetch_dimension_address_W(zval * container_ptr,zval * dim,int dim_type OPLINE_DC EXECUTE_DATA_DC)2606 static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_W(zval *container_ptr, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
2607 {
2608 	zval *result = EX_VAR(opline->result.var);
2609 	zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W EXECUTE_DATA_CC);
2610 }
2611 
zend_fetch_dimension_address_RW(zval * container_ptr,zval * dim,int dim_type OPLINE_DC EXECUTE_DATA_DC)2612 static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_RW(zval *container_ptr, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
2613 {
2614 	zval *result = EX_VAR(opline->result.var);
2615 	zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW EXECUTE_DATA_CC);
2616 }
2617 
zend_fetch_dimension_address_UNSET(zval * container_ptr,zval * dim,int dim_type OPLINE_DC EXECUTE_DATA_DC)2618 static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_UNSET(zval *container_ptr, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
2619 {
2620 	zval *result = EX_VAR(opline->result.var);
2621 	zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET EXECUTE_DATA_CC);
2622 }
2623 
zend_fetch_dimension_address_read(zval * result,zval * container,zval * dim,int dim_type,int type,bool is_list,int slow EXECUTE_DATA_DC)2624 static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, bool is_list, int slow EXECUTE_DATA_DC)
2625 {
2626 	zval *retval;
2627 
2628 	if (!slow) {
2629 		if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
2630 try_array:
2631 			retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type EXECUTE_DATA_CC);
2632 			ZVAL_COPY_DEREF(result, retval);
2633 			return;
2634 		} else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
2635 			container = Z_REFVAL_P(container);
2636 			if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
2637 				goto try_array;
2638 			}
2639 		}
2640 	}
2641 	if (!is_list && EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
2642 		zend_string *str = Z_STR_P(container);
2643 		zend_long offset;
2644 
2645 try_string_offset:
2646 		if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
2647 			switch (Z_TYPE_P(dim)) {
2648 				case IS_STRING:
2649 				{
2650 					bool trailing_data = false;
2651 					/* For BC reasons we allow errors so that we can warn on leading numeric string */
2652 					if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset,
2653 							NULL, /* allow errors */ true, NULL, &trailing_data)) {
2654 						if (UNEXPECTED(trailing_data)) {
2655 							zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
2656 						}
2657 						goto out;
2658 					}
2659 					if (type == BP_VAR_IS) {
2660 						ZVAL_NULL(result);
2661 						return;
2662 					}
2663 					zend_illegal_string_offset(dim);
2664 					ZVAL_NULL(result);
2665 					return;
2666 				}
2667 				case IS_UNDEF:
2668 					/* The string may be destroyed while throwing the notice.
2669 					 * Temporarily increase the refcount to detect this situation. */
2670 					if (!(GC_FLAGS(str) & IS_STR_INTERNED)) {
2671 						GC_ADDREF(str);
2672 					}
2673 					ZVAL_UNDEFINED_OP2();
2674 					if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) {
2675 						zend_string_efree(str);
2676 						ZVAL_NULL(result);
2677 						return;
2678 					}
2679 					ZEND_FALLTHROUGH;
2680 				case IS_DOUBLE:
2681 				case IS_NULL:
2682 				case IS_FALSE:
2683 				case IS_TRUE:
2684 					if (type != BP_VAR_IS) {
2685 						/* The string may be destroyed while throwing the notice.
2686 						 * Temporarily increase the refcount to detect this situation. */
2687 						if (!(GC_FLAGS(str) & IS_STR_INTERNED)) {
2688 							GC_ADDREF(str);
2689 						}
2690 						zend_error(E_WARNING, "String offset cast occurred");
2691 						if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) {
2692 							zend_string_efree(str);
2693 							ZVAL_NULL(result);
2694 							return;
2695 						}
2696 					}
2697 					break;
2698 				case IS_REFERENCE:
2699 					dim = Z_REFVAL_P(dim);
2700 					goto try_string_offset;
2701 				default:
2702 					zend_illegal_string_offset(dim);
2703 					ZVAL_NULL(result);
2704 					return;
2705 			}
2706 
2707 			offset = zval_get_long_func(dim, /* is_strict */ false);
2708 		} else {
2709 			offset = Z_LVAL_P(dim);
2710 		}
2711 		out:
2712 
2713 		if (UNEXPECTED(ZSTR_LEN(str) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
2714 			if (type != BP_VAR_IS) {
2715 				zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset);
2716 				ZVAL_EMPTY_STRING(result);
2717 			} else {
2718 				ZVAL_NULL(result);
2719 			}
2720 		} else {
2721 			zend_uchar c;
2722 			zend_long real_offset;
2723 
2724 			real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
2725 				? (zend_long)ZSTR_LEN(str) + offset : offset;
2726 			c = (zend_uchar)ZSTR_VAL(str)[real_offset];
2727 
2728 			ZVAL_CHAR(result, c);
2729 		}
2730 	} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
2731 		zend_object *obj = Z_OBJ_P(container);
2732 
2733 		GC_ADDREF(obj);
2734 		if (ZEND_CONST_COND(dim_type == IS_CV, 1) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
2735 			dim = ZVAL_UNDEFINED_OP2();
2736 		}
2737 		if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
2738 			dim++;
2739 		}
2740 		retval = obj->handlers->read_dimension(obj, dim, type, result);
2741 
2742 		ZEND_ASSERT(result != NULL);
2743 		if (retval) {
2744 			if (result != retval) {
2745 				ZVAL_COPY_DEREF(result, retval);
2746 			} else if (UNEXPECTED(Z_ISREF_P(retval))) {
2747 				zend_unwrap_reference(result);
2748 			}
2749 		} else {
2750 			ZVAL_NULL(result);
2751 		}
2752 		if (UNEXPECTED(GC_DELREF(obj) == 0)) {
2753 			zend_objects_store_del(obj);
2754 		}
2755 	} else {
2756 		if (type != BP_VAR_IS && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
2757 			container = ZVAL_UNDEFINED_OP1();
2758 		}
2759 		if (ZEND_CONST_COND(dim_type == IS_CV, 1) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
2760 			ZVAL_UNDEFINED_OP2();
2761 		}
2762 		if (!is_list && type != BP_VAR_IS) {
2763 			zend_error(E_WARNING, "Trying to access array offset on value of type %s",
2764 				zend_zval_type_name(container));
2765 		}
2766 		ZVAL_NULL(result);
2767 	}
2768 }
2769 
zend_fetch_dimension_address_read_R(zval * container,zval * dim,int dim_type OPLINE_DC EXECUTE_DATA_DC)2770 static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
2771 {
2772 	zval *result = EX_VAR(opline->result.var);
2773 	zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0 EXECUTE_DATA_CC);
2774 }
2775 
zend_fetch_dimension_address_read_R_slow(zval * container,zval * dim OPLINE_DC EXECUTE_DATA_DC)2776 static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC)
2777 {
2778 	zval *result = EX_VAR(opline->result.var);
2779 	zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 0, 1 EXECUTE_DATA_CC);
2780 }
2781 
zend_fetch_dimension_address_read_IS(zval * container,zval * dim,int dim_type OPLINE_DC EXECUTE_DATA_DC)2782 static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
2783 {
2784 	zval *result = EX_VAR(opline->result.var);
2785 	zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 0, 0 EXECUTE_DATA_CC);
2786 }
2787 
zend_fetch_dimension_address_LIST_r(zval * container,zval * dim,int dim_type OPLINE_DC EXECUTE_DATA_DC)2788 static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC)
2789 {
2790 	zval *result = EX_VAR(opline->result.var);
2791 	zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0 EXECUTE_DATA_CC);
2792 }
2793 
zend_fetch_dimension_const(zval * result,zval * container,zval * dim,int type)2794 ZEND_API void zend_fetch_dimension_const(zval *result, zval *container, zval *dim, int type)
2795 {
2796 	zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 0, 0 NO_EXECUTE_DATA_CC);
2797 }
2798 
zend_find_array_dim_slow(HashTable * ht,zval * offset EXECUTE_DATA_DC)2799 static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable *ht, zval *offset EXECUTE_DATA_DC)
2800 {
2801 	zend_ulong hval;
2802 
2803 	if (Z_TYPE_P(offset) == IS_DOUBLE) {
2804 		hval = zend_dval_to_lval_safe(Z_DVAL_P(offset));
2805 num_idx:
2806 		return zend_hash_index_find(ht, hval);
2807 	} else if (Z_TYPE_P(offset) == IS_NULL) {
2808 str_idx:
2809 		return zend_hash_find_known_hash(ht, ZSTR_EMPTY_ALLOC());
2810 	} else if (Z_TYPE_P(offset) == IS_FALSE) {
2811 		hval = 0;
2812 		goto num_idx;
2813 	} else if (Z_TYPE_P(offset) == IS_TRUE) {
2814 		hval = 1;
2815 		goto num_idx;
2816 	} else if (Z_TYPE_P(offset) == IS_RESOURCE) {
2817 		zend_use_resource_as_offset(offset);
2818 		hval = Z_RES_HANDLE_P(offset);
2819 		goto num_idx;
2820 	} else if (/*OP2_TYPE == IS_CV &&*/ Z_TYPE_P(offset) == IS_UNDEF) {
2821 		ZVAL_UNDEFINED_OP2();
2822 		goto str_idx;
2823 	} else {
2824 		zend_type_error("Illegal offset type in isset or empty");
2825 		return NULL;
2826 	}
2827 }
2828 
zend_isset_dim_slow(zval * container,zval * offset EXECUTE_DATA_DC)2829 static zend_never_inline bool ZEND_FASTCALL zend_isset_dim_slow(zval *container, zval *offset EXECUTE_DATA_DC)
2830 {
2831 	if (/*OP2_TYPE == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
2832 		offset = ZVAL_UNDEFINED_OP2();
2833 	}
2834 
2835 	if (/*OP1_TYPE != IS_CONST &&*/ EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
2836 		return Z_OBJ_HT_P(container)->has_dimension(Z_OBJ_P(container), offset, 0);
2837 	} else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
2838 		zend_long lval;
2839 
2840 		if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
2841 			lval = Z_LVAL_P(offset);
2842 str_offset:
2843 			if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
2844 				lval += (zend_long)Z_STRLEN_P(container);
2845 			}
2846 			if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
2847 				return 1;
2848 			} else {
2849 				return 0;
2850 			}
2851 		} else {
2852 			/*if (OP2_TYPE & (IS_CV|IS_VAR)) {*/
2853 				ZVAL_DEREF(offset);
2854 			/*}*/
2855 			if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
2856 					|| (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
2857 						&& IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) {
2858 				lval = zval_get_long_ex(offset, /* is_strict */ true);
2859 				goto str_offset;
2860 			}
2861 			return 0;
2862 		}
2863 	} else {
2864 		return 0;
2865 	}
2866 }
2867 
zend_isempty_dim_slow(zval * container,zval * offset EXECUTE_DATA_DC)2868 static zend_never_inline bool ZEND_FASTCALL zend_isempty_dim_slow(zval *container, zval *offset EXECUTE_DATA_DC)
2869 {
2870 	if (/*OP2_TYPE == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
2871 		offset = ZVAL_UNDEFINED_OP2();
2872 	}
2873 
2874 	if (/*OP1_TYPE != IS_CONST &&*/ EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
2875 		return !Z_OBJ_HT_P(container)->has_dimension(Z_OBJ_P(container), offset, 1);
2876 	} else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
2877 		zend_long lval;
2878 
2879 		if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
2880 			lval = Z_LVAL_P(offset);
2881 str_offset:
2882 			if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
2883 				lval += (zend_long)Z_STRLEN_P(container);
2884 			}
2885 			if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
2886 				return (Z_STRVAL_P(container)[lval] == '0');
2887 			} else {
2888 				return 1;
2889 			}
2890 		} else {
2891 			/*if (OP2_TYPE & (IS_CV|IS_VAR)) {*/
2892 				ZVAL_DEREF(offset);
2893 			/*}*/
2894 			if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
2895 					|| (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
2896 						&& IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) {
2897 				lval = zval_get_long_ex(offset, /* is_strict */ true);
2898 				goto str_offset;
2899 			}
2900 			return 1;
2901 		}
2902 	} else {
2903 		return 1;
2904 	}
2905 }
2906 
zend_array_key_exists_fast(HashTable * ht,zval * key OPLINE_DC EXECUTE_DATA_DC)2907 static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable *ht, zval *key OPLINE_DC EXECUTE_DATA_DC)
2908 {
2909 	zend_string *str;
2910 	zend_ulong hval;
2911 
2912 try_again:
2913 	if (EXPECTED(Z_TYPE_P(key) == IS_STRING)) {
2914 		str = Z_STR_P(key);
2915 		if (ZEND_HANDLE_NUMERIC(str, hval)) {
2916 			goto num_key;
2917 		}
2918 str_key:
2919 		return zend_hash_exists(ht, str);
2920 	} else if (EXPECTED(Z_TYPE_P(key) == IS_LONG)) {
2921 		hval = Z_LVAL_P(key);
2922 num_key:
2923 		return zend_hash_index_exists(ht, hval);
2924 	} else if (EXPECTED(Z_ISREF_P(key))) {
2925 		key = Z_REFVAL_P(key);
2926 		goto try_again;
2927 	} else if (Z_TYPE_P(key) == IS_DOUBLE) {
2928 		hval = zend_dval_to_lval_safe(Z_DVAL_P(key));
2929 		goto num_key;
2930 	} else if (Z_TYPE_P(key) == IS_FALSE) {
2931 		hval = 0;
2932 		goto num_key;
2933 	} else if (Z_TYPE_P(key) == IS_TRUE) {
2934 		hval = 1;
2935 		goto num_key;
2936 	} else if (Z_TYPE_P(key) == IS_RESOURCE) {
2937 		zend_use_resource_as_offset(key);
2938 		hval = Z_RES_HANDLE_P(key);
2939 		goto num_key;
2940 	} else if (Z_TYPE_P(key) <= IS_NULL) {
2941 		if (UNEXPECTED(Z_TYPE_P(key) == IS_UNDEF)) {
2942 			ZVAL_UNDEFINED_OP1();
2943 		}
2944 		str = ZSTR_EMPTY_ALLOC();
2945 		goto str_key;
2946 	} else {
2947 		zend_illegal_offset();
2948 		return 0;
2949 	}
2950 }
2951 
zend_array_key_exists_error(zval * subject,zval * key OPLINE_DC EXECUTE_DATA_DC)2952 static ZEND_COLD void ZEND_FASTCALL zend_array_key_exists_error(
2953 		zval *subject, zval *key OPLINE_DC EXECUTE_DATA_DC)
2954 {
2955 	if (Z_TYPE_P(key) == IS_UNDEF) {
2956 		ZVAL_UNDEFINED_OP1();
2957 	}
2958 	if (Z_TYPE_P(subject) == IS_UNDEF) {
2959 		ZVAL_UNDEFINED_OP2();
2960 	}
2961 	if (!EG(exception)) {
2962 		zend_type_error("array_key_exists(): Argument #2 ($array) must be of type array, %s given",
2963 			zend_zval_type_name(subject));
2964 	}
2965 }
2966 
promotes_to_array(zval * val)2967 static zend_always_inline bool promotes_to_array(zval *val) {
2968 	return Z_TYPE_P(val) <= IS_FALSE
2969 		|| (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE);
2970 }
2971 
check_type_array_assignable(zend_type type)2972 static zend_always_inline bool check_type_array_assignable(zend_type type) {
2973 	if (!ZEND_TYPE_IS_SET(type)) {
2974 		return 1;
2975 	}
2976 	return (ZEND_TYPE_FULL_MASK(type) & MAY_BE_ARRAY) != 0;
2977 }
2978 
2979 /* Checks whether an array can be assigned to the reference. Throws error if not assignable. */
zend_verify_ref_array_assignable(zend_reference * ref)2980 ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref) {
2981 	zend_property_info *prop;
2982 	ZEND_ASSERT(ZEND_REF_HAS_TYPE_SOURCES(ref));
2983 	ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
2984 		if (!check_type_array_assignable(prop->type)) {
2985 			zend_throw_auto_init_in_ref_error(prop);
2986 			return 0;
2987 		}
2988 	} ZEND_REF_FOREACH_TYPE_SOURCES_END();
2989 	return 1;
2990 }
2991 
zend_object_fetch_property_type_info(zend_object * obj,zval * slot)2992 static zend_property_info *zend_object_fetch_property_type_info(
2993 		zend_object *obj, zval *slot)
2994 {
2995 	if (EXPECTED(!ZEND_CLASS_HAS_TYPE_HINTS(obj->ce))) {
2996 		return NULL;
2997 	}
2998 
2999 	/* Not a declared property */
3000 	if (UNEXPECTED(slot < obj->properties_table ||
3001 			slot >= obj->properties_table + obj->ce->default_properties_count)) {
3002 		return NULL;
3003 	}
3004 
3005 	return zend_get_typed_property_info_for_slot(obj, slot);
3006 }
3007 
zend_handle_fetch_obj_flags(zval * result,zval * ptr,zend_object * obj,zend_property_info * prop_info,uint32_t flags)3008 static zend_never_inline bool zend_handle_fetch_obj_flags(
3009 		zval *result, zval *ptr, zend_object *obj, zend_property_info *prop_info, uint32_t flags)
3010 {
3011 	switch (flags) {
3012 		case ZEND_FETCH_DIM_WRITE:
3013 			if (promotes_to_array(ptr)) {
3014 				if (!prop_info) {
3015 					prop_info = zend_object_fetch_property_type_info(obj, ptr);
3016 					if (!prop_info) {
3017 						break;
3018 					}
3019 				}
3020 				if (!check_type_array_assignable(prop_info->type)) {
3021 					zend_throw_auto_init_in_prop_error(prop_info);
3022 					if (result) ZVAL_ERROR(result);
3023 					return 0;
3024 				}
3025 			}
3026 			break;
3027 		case ZEND_FETCH_REF:
3028 			if (Z_TYPE_P(ptr) != IS_REFERENCE) {
3029 				if (!prop_info) {
3030 					prop_info = zend_object_fetch_property_type_info(obj, ptr);
3031 					if (!prop_info) {
3032 						break;
3033 					}
3034 				}
3035 				if (Z_TYPE_P(ptr) == IS_UNDEF) {
3036 					if (!ZEND_TYPE_ALLOW_NULL(prop_info->type)) {
3037 						zend_throw_access_uninit_prop_by_ref_error(prop_info);
3038 						if (result) ZVAL_ERROR(result);
3039 						return 0;
3040 					}
3041 					ZVAL_NULL(ptr);
3042 				}
3043 
3044 				ZVAL_NEW_REF(ptr, ptr);
3045 				ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(ptr), prop_info);
3046 			}
3047 			break;
3048 		EMPTY_SWITCH_DEFAULT_CASE()
3049 	}
3050 	return 1;
3051 }
3052 
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,uint32_t flags OPLINE_DC EXECUTE_DATA_DC)3053 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, uint32_t flags OPLINE_DC EXECUTE_DATA_DC)
3054 {
3055 	zval *ptr;
3056 	zend_object *zobj;
3057 	zend_string *name, *tmp_name;
3058 
3059 	if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) {
3060 		do {
3061 			if (Z_ISREF_P(container) && Z_TYPE_P(Z_REFVAL_P(container)) == IS_OBJECT) {
3062 				container = Z_REFVAL_P(container);
3063 				break;
3064 			}
3065 
3066 			if (container_op_type == IS_CV
3067 			 && type != BP_VAR_W
3068 			 && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
3069 				ZVAL_UNDEFINED_OP1();
3070 			}
3071 
3072 			/* this should modify object only if it's empty */
3073 			if (type == BP_VAR_UNSET) {
3074 				ZVAL_NULL(result);
3075 				return;
3076 			}
3077 
3078 			zend_throw_non_object_error(container, prop_ptr OPLINE_CC EXECUTE_DATA_CC);
3079 			ZVAL_ERROR(result);
3080 			return;
3081 		} while (0);
3082 	}
3083 
3084 	zobj = Z_OBJ_P(container);
3085 	if (prop_op_type == IS_CONST &&
3086 	    EXPECTED(zobj->ce == CACHED_PTR_EX(cache_slot))) {
3087 		uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
3088 
3089 		if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
3090 			ptr = OBJ_PROP(zobj, prop_offset);
3091 			if (EXPECTED(Z_TYPE_P(ptr) != IS_UNDEF)) {
3092 				ZVAL_INDIRECT(result, ptr);
3093 				zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2);
3094 				if (prop_info) {
3095 					if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
3096 						/* For objects, W/RW/UNSET fetch modes might not actually modify object.
3097 						 * Similar as with magic __get() allow them, but return the value as a copy
3098 						 * to make sure no actual modification is possible. */
3099 						ZEND_ASSERT(type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET);
3100 						if (Z_TYPE_P(ptr) == IS_OBJECT) {
3101 							ZVAL_COPY(result, ptr);
3102 						} else {
3103 							zend_readonly_property_modification_error(prop_info);
3104 							ZVAL_ERROR(result);
3105 						}
3106 						return;
3107 					}
3108 					flags &= ZEND_FETCH_OBJ_FLAGS;
3109 					if (flags) {
3110 						zend_handle_fetch_obj_flags(result, ptr, NULL, prop_info, flags);
3111 					}
3112 				}
3113 				return;
3114 			}
3115 		} else if (EXPECTED(zobj->properties != NULL)) {
3116 			if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
3117 				if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
3118 					GC_DELREF(zobj->properties);
3119 				}
3120 				zobj->properties = zend_array_dup(zobj->properties);
3121 			}
3122 			ptr = zend_hash_find_known_hash(zobj->properties, Z_STR_P(prop_ptr));
3123 			if (EXPECTED(ptr)) {
3124 				ZVAL_INDIRECT(result, ptr);
3125 				return;
3126 			}
3127 		}
3128 	}
3129 
3130 	/* Pointer on property callback is required */
3131 	ZEND_ASSERT(zobj->handlers->get_property_ptr_ptr != NULL);
3132 
3133 	if (prop_op_type == IS_CONST) {
3134 		name = Z_STR_P(prop_ptr);
3135 	} else {
3136 		name = zval_get_tmp_string(prop_ptr, &tmp_name);
3137 	}
3138 	ptr = zobj->handlers->get_property_ptr_ptr(zobj, name, type, cache_slot);
3139 	if (NULL == ptr) {
3140 		ptr = zobj->handlers->read_property(zobj, name, type, cache_slot, result);
3141 		if (ptr == result) {
3142 			if (UNEXPECTED(Z_ISREF_P(ptr) && Z_REFCOUNT_P(ptr) == 1)) {
3143 				ZVAL_UNREF(ptr);
3144 			}
3145 			goto end;
3146 		}
3147 		if (UNEXPECTED(EG(exception))) {
3148 			ZVAL_ERROR(result);
3149 			goto end;
3150 		}
3151 	} else if (UNEXPECTED(Z_ISERROR_P(ptr))) {
3152 		ZVAL_ERROR(result);
3153 		goto end;
3154 	}
3155 
3156 	ZVAL_INDIRECT(result, ptr);
3157 	flags &= ZEND_FETCH_OBJ_FLAGS;
3158 	if (flags) {
3159 		zend_property_info *prop_info;
3160 
3161 		if (prop_op_type == IS_CONST) {
3162 			prop_info = CACHED_PTR_EX(cache_slot + 2);
3163 			if (prop_info) {
3164 				if (UNEXPECTED(!zend_handle_fetch_obj_flags(result, ptr, NULL, prop_info, flags))) {
3165 					goto end;
3166 				}
3167 			}
3168 		} else {
3169 			if (UNEXPECTED(!zend_handle_fetch_obj_flags(result, ptr, Z_OBJ_P(container), NULL, flags))) {
3170 				goto end;
3171 			}
3172 		}
3173 	}
3174 
3175 end:
3176 	if (prop_op_type != IS_CONST) {
3177 		zend_tmp_string_release(tmp_name);
3178 	}
3179 }
3180 
zend_assign_to_property_reference(zval * container,uint32_t container_op_type,zval * prop_ptr,uint32_t prop_op_type,zval * value_ptr OPLINE_DC EXECUTE_DATA_DC)3181 static zend_always_inline void zend_assign_to_property_reference(zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
3182 {
3183 	zval variable, *variable_ptr = &variable;
3184 	void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_RETURNS_FUNCTION) : NULL;
3185 
3186 	zend_fetch_property_address(variable_ptr, container, container_op_type, prop_ptr, prop_op_type,
3187 		cache_addr, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
3188 
3189 	if (EXPECTED(Z_TYPE_P(variable_ptr) == IS_INDIRECT)) {
3190 		variable_ptr = Z_INDIRECT_P(variable_ptr);
3191 		if (/*OP_DATA_TYPE == IS_VAR &&*/
3192 				   (opline->extended_value & ZEND_RETURNS_FUNCTION) &&
3193 				   UNEXPECTED(!Z_ISREF_P(value_ptr))) {
3194 
3195 			variable_ptr = zend_wrong_assign_to_variable_reference(
3196 				variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC);
3197 		} else {
3198 			zend_property_info *prop_info = NULL;
3199 
3200 			if (prop_op_type == IS_CONST) {
3201 				prop_info = (zend_property_info *) CACHED_PTR_EX(cache_addr + 2);
3202 			} else {
3203 				ZVAL_DEREF(container);
3204 				prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(container), variable_ptr);
3205 			}
3206 
3207 			if (UNEXPECTED(prop_info)) {
3208 				variable_ptr = zend_assign_to_typed_property_reference(prop_info, variable_ptr, value_ptr EXECUTE_DATA_CC);
3209 			} else {
3210 				zend_assign_to_variable_reference(variable_ptr, value_ptr);
3211 			}
3212 		}
3213 	} else if (Z_ISERROR_P(variable_ptr)) {
3214 		variable_ptr = &EG(uninitialized_zval);
3215 	} else {
3216 		zend_throw_error(NULL, "Cannot assign by reference to overloaded object");
3217 		zval_ptr_dtor(&variable);
3218 		variable_ptr = &EG(uninitialized_zval);
3219 	}
3220 
3221 	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
3222 		ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr);
3223 	}
3224 }
3225 
zend_assign_to_property_reference_this_const(zval * container,zval * prop_ptr,zval * value_ptr OPLINE_DC EXECUTE_DATA_DC)3226 static zend_never_inline void zend_assign_to_property_reference_this_const(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
3227 {
3228 	zend_assign_to_property_reference(container, IS_UNUSED, prop_ptr, IS_CONST, value_ptr
3229 		OPLINE_CC EXECUTE_DATA_CC);
3230 }
3231 
zend_assign_to_property_reference_var_const(zval * container,zval * prop_ptr,zval * value_ptr OPLINE_DC EXECUTE_DATA_DC)3232 static zend_never_inline void zend_assign_to_property_reference_var_const(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
3233 {
3234 	zend_assign_to_property_reference(container, IS_VAR, prop_ptr, IS_CONST, value_ptr
3235 		OPLINE_CC EXECUTE_DATA_CC);
3236 }
3237 
zend_assign_to_property_reference_this_var(zval * container,zval * prop_ptr,zval * value_ptr OPLINE_DC EXECUTE_DATA_DC)3238 static zend_never_inline void zend_assign_to_property_reference_this_var(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
3239 {
3240 	zend_assign_to_property_reference(container, IS_UNUSED, prop_ptr, IS_VAR, value_ptr
3241 		OPLINE_CC EXECUTE_DATA_CC);
3242 }
3243 
zend_assign_to_property_reference_var_var(zval * container,zval * prop_ptr,zval * value_ptr OPLINE_DC EXECUTE_DATA_DC)3244 static zend_never_inline void zend_assign_to_property_reference_var_var(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC)
3245 {
3246 	zend_assign_to_property_reference(container, IS_VAR, prop_ptr, IS_VAR, value_ptr
3247 		OPLINE_CC EXECUTE_DATA_CC);
3248 }
3249 
zend_fetch_static_property_address_ex(zval ** retval,zend_property_info ** prop_info,uint32_t cache_slot,int fetch_type OPLINE_DC EXECUTE_DATA_DC)3250 static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval **retval, zend_property_info **prop_info, uint32_t cache_slot, int fetch_type OPLINE_DC EXECUTE_DATA_DC) {
3251 	zend_string *name;
3252 	zend_class_entry *ce;
3253 	zend_property_info *property_info;
3254 
3255 	zend_uchar op1_type = opline->op1_type, op2_type = opline->op2_type;
3256 
3257 	if (EXPECTED(op2_type == IS_CONST)) {
3258 		zval *class_name = RT_CONSTANT(opline, opline->op2);
3259 
3260 		ZEND_ASSERT(op1_type != IS_CONST || CACHED_PTR(cache_slot) == NULL);
3261 
3262 		if (EXPECTED((ce = CACHED_PTR(cache_slot)) == NULL)) {
3263 			ce = zend_fetch_class_by_name(Z_STR_P(class_name), Z_STR_P(class_name + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
3264 			if (UNEXPECTED(ce == NULL)) {
3265 				FREE_OP(op1_type, opline->op1.var);
3266 				return FAILURE;
3267 			}
3268 			if (UNEXPECTED(op1_type != IS_CONST)) {
3269 				CACHE_PTR(cache_slot, ce);
3270 			}
3271 		}
3272 	} else {
3273 		if (EXPECTED(op2_type == IS_UNUSED)) {
3274 			ce = zend_fetch_class(NULL, opline->op2.num);
3275 			if (UNEXPECTED(ce == NULL)) {
3276 				FREE_OP(op1_type, opline->op1.var);
3277 				return FAILURE;
3278 			}
3279 		} else {
3280 			ce = Z_CE_P(EX_VAR(opline->op2.var));
3281 		}
3282 		if (EXPECTED(op1_type == IS_CONST) && EXPECTED(CACHED_PTR(cache_slot) == ce)) {
3283 			*retval = CACHED_PTR(cache_slot + sizeof(void *));
3284 			*prop_info = CACHED_PTR(cache_slot + sizeof(void *) * 2);
3285 			return SUCCESS;
3286 		}
3287 	}
3288 
3289 	if (EXPECTED(op1_type == IS_CONST)) {
3290 		name = Z_STR_P(RT_CONSTANT(opline, opline->op1));
3291 		*retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info);
3292 	} else {
3293 		zend_string *tmp_name;
3294 		zval *varname = get_zval_ptr_undef(opline->op1_type, opline->op1, BP_VAR_R);
3295 		if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) {
3296 			name = Z_STR_P(varname);
3297 			tmp_name = NULL;
3298 		} else {
3299 			if (op1_type == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) {
3300 				zval_undefined_cv(opline->op1.var EXECUTE_DATA_CC);
3301 			}
3302 			name = zval_get_tmp_string(varname, &tmp_name);
3303 		}
3304 		*retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info);
3305 
3306 		if (UNEXPECTED(op1_type != IS_CONST)) {
3307 			zend_tmp_string_release(tmp_name);
3308 
3309 			FREE_OP(op1_type, opline->op1.var);
3310 		}
3311 	}
3312 
3313 	if (UNEXPECTED(*retval == NULL)) {
3314 		return FAILURE;
3315 	}
3316 
3317 	*prop_info = property_info;
3318 
3319 	if (EXPECTED(op1_type == IS_CONST)
3320 			&& EXPECTED(!(property_info->ce->ce_flags & ZEND_ACC_TRAIT))) {
3321 		CACHE_POLYMORPHIC_PTR(cache_slot, ce, *retval);
3322 		CACHE_PTR(cache_slot + sizeof(void *) * 2, property_info);
3323 	}
3324 
3325 	return SUCCESS;
3326 }
3327 
3328 
zend_fetch_static_property_address(zval ** retval,zend_property_info ** prop_info,uint32_t cache_slot,int fetch_type,int flags OPLINE_DC EXECUTE_DATA_DC)3329 static zend_always_inline zend_result zend_fetch_static_property_address(zval **retval, zend_property_info **prop_info, uint32_t cache_slot, int fetch_type, int flags OPLINE_DC EXECUTE_DATA_DC) {
3330 	zend_property_info *property_info;
3331 
3332 	if (opline->op1_type == IS_CONST && (opline->op2_type == IS_CONST || (opline->op2_type == IS_UNUSED && (opline->op2.num == ZEND_FETCH_CLASS_SELF || opline->op2.num == ZEND_FETCH_CLASS_PARENT))) && EXPECTED(CACHED_PTR(cache_slot) != NULL)) {
3333 		*retval = CACHED_PTR(cache_slot + sizeof(void *));
3334 		property_info = CACHED_PTR(cache_slot + sizeof(void *) * 2);
3335 
3336 		if ((fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW)
3337 				&& UNEXPECTED(Z_TYPE_P(*retval) == IS_UNDEF)
3338 				&& UNEXPECTED(ZEND_TYPE_IS_SET(property_info->type))) {
3339 			zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
3340 				ZSTR_VAL(property_info->ce->name),
3341 				zend_get_unmangled_property_name(property_info->name));
3342 			return FAILURE;
3343 		}
3344 	} else {
3345 		zend_result success;
3346 		success = zend_fetch_static_property_address_ex(retval, &property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC);
3347 		if (UNEXPECTED(success != SUCCESS)) {
3348 			return FAILURE;
3349 		}
3350 	}
3351 
3352 	flags &= ZEND_FETCH_OBJ_FLAGS;
3353 	if (flags && ZEND_TYPE_IS_SET(property_info->type)) {
3354 		zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
3355 	}
3356 
3357 	if (prop_info) {
3358 		*prop_info = property_info;
3359 	}
3360 
3361 	return SUCCESS;
3362 }
3363 
zend_throw_ref_type_error_type(zend_property_info * prop1,zend_property_info * prop2,zval * zv)3364 ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(zend_property_info *prop1, zend_property_info *prop2, zval *zv) {
3365 	zend_string *type1_str = zend_type_to_string(prop1->type);
3366 	zend_string *type2_str = zend_type_to_string(prop2->type);
3367 	zend_type_error("Reference with value of type %s held by property %s::$%s of type %s is not compatible with property %s::$%s of type %s",
3368 		zend_zval_type_name(zv),
3369 		ZSTR_VAL(prop1->ce->name),
3370 		zend_get_unmangled_property_name(prop1->name),
3371 		ZSTR_VAL(type1_str),
3372 		ZSTR_VAL(prop2->ce->name),
3373 		zend_get_unmangled_property_name(prop2->name),
3374 		ZSTR_VAL(type2_str)
3375 	);
3376 	zend_string_release(type1_str);
3377 	zend_string_release(type2_str);
3378 }
3379 
zend_throw_ref_type_error_zval(zend_property_info * prop,zval * zv)3380 ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(zend_property_info *prop, zval *zv) {
3381 	zend_string *type_str = zend_type_to_string(prop->type);
3382 	zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s",
3383 		zend_zval_type_name(zv),
3384 		ZSTR_VAL(prop->ce->name),
3385 		zend_get_unmangled_property_name(prop->name),
3386 		ZSTR_VAL(type_str)
3387 	);
3388 	zend_string_release(type_str);
3389 }
3390 
zend_throw_conflicting_coercion_error(zend_property_info * prop1,zend_property_info * prop2,zval * zv)3391 ZEND_API ZEND_COLD void zend_throw_conflicting_coercion_error(zend_property_info *prop1, zend_property_info *prop2, zval *zv) {
3392 	zend_string *type1_str = zend_type_to_string(prop1->type);
3393 	zend_string *type2_str = zend_type_to_string(prop2->type);
3394 	zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s and property %s::$%s of type %s, as this would result in an inconsistent type conversion",
3395 		zend_zval_type_name(zv),
3396 		ZSTR_VAL(prop1->ce->name),
3397 		zend_get_unmangled_property_name(prop1->name),
3398 		ZSTR_VAL(type1_str),
3399 		ZSTR_VAL(prop2->ce->name),
3400 		zend_get_unmangled_property_name(prop2->name),
3401 		ZSTR_VAL(type2_str)
3402 	);
3403 	zend_string_release(type1_str);
3404 	zend_string_release(type2_str);
3405 }
3406 
3407 /* 1: valid, 0: invalid, -1: may be valid after type coercion */
i_zend_verify_type_assignable_zval(zend_property_info * info,zval * zv,bool strict)3408 static zend_always_inline int i_zend_verify_type_assignable_zval(
3409 		zend_property_info *info, zval *zv, bool strict) {
3410 	zend_type type = info->type;
3411 	uint32_t type_mask;
3412 	zend_uchar zv_type = Z_TYPE_P(zv);
3413 
3414 	if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(type, zv_type))) {
3415 		return 1;
3416 	}
3417 
3418 	if (ZEND_TYPE_IS_COMPLEX(type) && zv_type == IS_OBJECT
3419 			&& zend_check_and_resolve_property_class_type(info, Z_OBJCE_P(zv))) {
3420 		return 1;
3421 	}
3422 
3423 	type_mask = ZEND_TYPE_FULL_MASK(type);
3424 	ZEND_ASSERT(!(type_mask & (MAY_BE_CALLABLE|MAY_BE_STATIC)));
3425 
3426 	/* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
3427 	if (strict) {
3428 		if ((type_mask & MAY_BE_DOUBLE) && zv_type == IS_LONG) {
3429 			return -1;
3430 		}
3431 		return 0;
3432 	}
3433 
3434 	/* NULL may be accepted only by nullable hints (this is already checked) */
3435 	if (zv_type == IS_NULL) {
3436 		return 0;
3437 	}
3438 
3439 	/* Does not contain any type to which a coercion is possible */
3440 	if (!(type_mask & (MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING))
3441 			&& (type_mask & MAY_BE_BOOL) != MAY_BE_BOOL) {
3442 		return 0;
3443 	}
3444 
3445 	/* Coercion may be necessary, check separately */
3446 	return -1;
3447 }
3448 
zend_verify_ref_assignable_zval(zend_reference * ref,zval * zv,bool strict)3449 ZEND_API bool ZEND_FASTCALL zend_verify_ref_assignable_zval(zend_reference *ref, zval *zv, bool strict)
3450 {
3451 	zend_property_info *prop;
3452 
3453 	/* The value must satisfy each property type, and coerce to the same value for each property
3454 	 * type. Remember the first coerced type and value we've seen for this purpose. */
3455 	zend_property_info *first_prop = NULL;
3456 	zval coerced_value;
3457 	ZVAL_UNDEF(&coerced_value);
3458 
3459 	ZEND_ASSERT(Z_TYPE_P(zv) != IS_REFERENCE);
3460 	ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
3461 		int result = i_zend_verify_type_assignable_zval(prop, zv, strict);
3462 		if (result == 0) {
3463 type_error:
3464 			zend_throw_ref_type_error_zval(prop, zv);
3465 			zval_ptr_dtor(&coerced_value);
3466 			return 0;
3467 		}
3468 
3469 		if (result < 0) {
3470 			if (!first_prop) {
3471 				first_prop = prop;
3472 				ZVAL_COPY(&coerced_value, zv);
3473 				if (!zend_verify_weak_scalar_type_hint(
3474 						ZEND_TYPE_FULL_MASK(prop->type), &coerced_value)) {
3475 					goto type_error;
3476 				}
3477 			} else if (Z_ISUNDEF(coerced_value)) {
3478 				/* A previous property did not require coercion, but this one does,
3479 				 * so they are incompatible. */
3480 				goto conflicting_coercion_error;
3481 			} else {
3482 				zval tmp;
3483 				ZVAL_COPY(&tmp, zv);
3484 				if (!zend_verify_weak_scalar_type_hint(ZEND_TYPE_FULL_MASK(prop->type), &tmp)) {
3485 					zval_ptr_dtor(&tmp);
3486 					goto type_error;
3487 				}
3488 				if (!zend_is_identical(&coerced_value, &tmp)) {
3489 					zval_ptr_dtor(&tmp);
3490 					goto conflicting_coercion_error;
3491 				}
3492 				zval_ptr_dtor(&tmp);
3493 			}
3494 		} else {
3495 			if (!first_prop) {
3496 				first_prop = prop;
3497 			} else if (!Z_ISUNDEF(coerced_value)) {
3498 				/* A previous property required coercion, but this one doesn't,
3499 				 * so they are incompatible. */
3500 conflicting_coercion_error:
3501 				zend_throw_conflicting_coercion_error(first_prop, prop, zv);
3502 				zval_ptr_dtor(&coerced_value);
3503 				return 0;
3504 			}
3505 		}
3506 	} ZEND_REF_FOREACH_TYPE_SOURCES_END();
3507 
3508 	if (!Z_ISUNDEF(coerced_value)) {
3509 		zval_ptr_dtor(zv);
3510 		ZVAL_COPY_VALUE(zv, &coerced_value);
3511 	}
3512 
3513 	return 1;
3514 }
3515 
i_zval_ptr_dtor_noref(zval * zval_ptr)3516 static zend_always_inline void i_zval_ptr_dtor_noref(zval *zval_ptr) {
3517 	if (Z_REFCOUNTED_P(zval_ptr)) {
3518 		zend_refcounted *ref = Z_COUNTED_P(zval_ptr);
3519 		ZEND_ASSERT(Z_TYPE_P(zval_ptr) != IS_REFERENCE);
3520 		if (!GC_DELREF(ref)) {
3521 			rc_dtor_func(ref);
3522 		} else if (UNEXPECTED(GC_MAY_LEAK(ref))) {
3523 			gc_possible_root(ref);
3524 		}
3525 	}
3526 }
3527 
zend_assign_to_typed_ref(zval * variable_ptr,zval * orig_value,zend_uchar value_type,bool strict)3528 ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, zend_uchar value_type, bool strict)
3529 {
3530 	bool ret;
3531 	zval value;
3532 	zend_refcounted *ref = NULL;
3533 
3534 	if (Z_ISREF_P(orig_value)) {
3535 		ref = Z_COUNTED_P(orig_value);
3536 		orig_value = Z_REFVAL_P(orig_value);
3537 	}
3538 
3539 	ZVAL_COPY(&value, orig_value);
3540 	ret = zend_verify_ref_assignable_zval(Z_REF_P(variable_ptr), &value, strict);
3541 	variable_ptr = Z_REFVAL_P(variable_ptr);
3542 	if (EXPECTED(ret)) {
3543 		i_zval_ptr_dtor_noref(variable_ptr);
3544 		ZVAL_COPY_VALUE(variable_ptr, &value);
3545 	} else {
3546 		zval_ptr_dtor_nogc(&value);
3547 	}
3548 	if (value_type & (IS_VAR|IS_TMP_VAR)) {
3549 		if (UNEXPECTED(ref)) {
3550 			if (UNEXPECTED(GC_DELREF(ref) == 0)) {
3551 				zval_ptr_dtor(orig_value);
3552 				efree_size(ref, sizeof(zend_reference));
3553 			}
3554 		} else {
3555 			i_zval_ptr_dtor_noref(orig_value);
3556 		}
3557 	}
3558 	return variable_ptr;
3559 }
3560 
zend_verify_prop_assignable_by_ref(zend_property_info * prop_info,zval * orig_val,bool strict)3561 ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, bool strict) {
3562 	zval *val = orig_val;
3563 	if (Z_ISREF_P(val) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(val))) {
3564 		int result;
3565 
3566 		val = Z_REFVAL_P(val);
3567 		result = i_zend_verify_type_assignable_zval(prop_info, val, strict);
3568 		if (result > 0) {
3569 			return 1;
3570 		}
3571 
3572 		if (result < 0) {
3573 			/* This is definitely an error, but we still need to determined why: Either because
3574 			 * the value is simply illegal for the type, or because or a conflicting coercion. */
3575 			zval tmp;
3576 			ZVAL_COPY(&tmp, val);
3577 			if (zend_verify_weak_scalar_type_hint(ZEND_TYPE_FULL_MASK(prop_info->type), &tmp)) {
3578 				zend_property_info *ref_prop = ZEND_REF_FIRST_SOURCE(Z_REF_P(orig_val));
3579 				zend_throw_ref_type_error_type(ref_prop, prop_info, val);
3580 				zval_ptr_dtor(&tmp);
3581 				return 0;
3582 			}
3583 			zval_ptr_dtor(&tmp);
3584 		}
3585 	} else {
3586 		ZVAL_DEREF(val);
3587 		if (i_zend_check_property_type(prop_info, val, strict)) {
3588 			return 1;
3589 		}
3590 	}
3591 
3592 	zend_verify_property_type_error(prop_info, val);
3593 	return 0;
3594 }
3595 
zend_ref_add_type_source(zend_property_info_source_list * source_list,zend_property_info * prop)3596 ZEND_API void ZEND_FASTCALL zend_ref_add_type_source(zend_property_info_source_list *source_list, zend_property_info *prop)
3597 {
3598 	zend_property_info_list *list;
3599 	if (source_list->ptr == NULL) {
3600 		source_list->ptr = prop;
3601 		return;
3602 	}
3603 
3604 	list = ZEND_PROPERTY_INFO_SOURCE_TO_LIST(source_list->list);
3605 	if (!ZEND_PROPERTY_INFO_SOURCE_IS_LIST(source_list->list)) {
3606 		list = emalloc(sizeof(zend_property_info_list) + (4 - 1) * sizeof(zend_property_info *));
3607 		list->ptr[0] = source_list->ptr;
3608 		list->num_allocated = 4;
3609 		list->num = 1;
3610 	} else if (list->num_allocated == list->num) {
3611 		list->num_allocated = list->num * 2;
3612 		list = erealloc(list, sizeof(zend_property_info_list) + (list->num_allocated - 1) * sizeof(zend_property_info *));
3613 	}
3614 
3615 	list->ptr[list->num++] = prop;
3616 	source_list->list = ZEND_PROPERTY_INFO_SOURCE_FROM_LIST(list);
3617 }
3618 
zend_ref_del_type_source(zend_property_info_source_list * source_list,zend_property_info * prop)3619 ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, zend_property_info *prop)
3620 {
3621 	zend_property_info_list *list = ZEND_PROPERTY_INFO_SOURCE_TO_LIST(source_list->list);
3622 	zend_property_info **ptr, **end;
3623 
3624 	ZEND_ASSERT(prop);
3625 	if (!ZEND_PROPERTY_INFO_SOURCE_IS_LIST(source_list->list)) {
3626 		ZEND_ASSERT(source_list->ptr == prop);
3627 		source_list->ptr = NULL;
3628 		return;
3629 	}
3630 
3631 	if (list->num == 1) {
3632 		ZEND_ASSERT(*list->ptr == prop);
3633 		efree(list);
3634 		source_list->ptr = NULL;
3635 		return;
3636 	}
3637 
3638 	/* Checking against end here to get a more graceful failure mode if we missed adding a type
3639 	 * source at some point. */
3640 	ptr = list->ptr;
3641 	end = ptr + list->num;
3642 	while (ptr < end && *ptr != prop) {
3643 		ptr++;
3644 	}
3645 	ZEND_ASSERT(*ptr == prop);
3646 
3647 	/* Copy the last list element into the deleted slot. */
3648 	*ptr = list->ptr[--list->num];
3649 
3650 	if (list->num >= 4 && list->num * 4 == list->num_allocated) {
3651 		list->num_allocated = list->num * 2;
3652 		source_list->list = ZEND_PROPERTY_INFO_SOURCE_FROM_LIST(erealloc(list, sizeof(zend_property_info_list) + (list->num_allocated - 1) * sizeof(zend_property_info *)));
3653 	}
3654 }
3655 
zend_fetch_this_var(int type OPLINE_DC EXECUTE_DATA_DC)3656 static zend_never_inline void zend_fetch_this_var(int type OPLINE_DC EXECUTE_DATA_DC)
3657 {
3658 	zval *result = EX_VAR(opline->result.var);
3659 
3660 	switch (type) {
3661 		case BP_VAR_R:
3662 			if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
3663 				ZVAL_OBJ(result, Z_OBJ(EX(This)));
3664 				Z_ADDREF_P(result);
3665 			} else {
3666 				ZVAL_NULL(result);
3667 				zend_error(E_WARNING, "Undefined variable $this");
3668 			}
3669 			break;
3670 		case BP_VAR_IS:
3671 			if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
3672 				ZVAL_OBJ(result, Z_OBJ(EX(This)));
3673 				Z_ADDREF_P(result);
3674 			} else {
3675 				ZVAL_NULL(result);
3676 			}
3677 			break;
3678 		case BP_VAR_RW:
3679 		case BP_VAR_W:
3680 			ZVAL_UNDEF(result);
3681 			zend_throw_error(NULL, "Cannot re-assign $this");
3682 			break;
3683 		case BP_VAR_UNSET:
3684 			ZVAL_UNDEF(result);
3685 			zend_throw_error(NULL, "Cannot unset $this");
3686 			break;
3687 		EMPTY_SWITCH_DEFAULT_CASE()
3688 	}
3689 }
3690 
zend_wrong_clone_call(zend_function * clone,zend_class_entry * scope)3691 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_clone_call(zend_function *clone, zend_class_entry *scope)
3692 {
3693 	zend_throw_error(NULL, "Call to %s %s::__clone() from %s%s",
3694 		zend_visibility_string(clone->common.fn_flags), ZSTR_VAL(clone->common.scope->name),
3695 		scope ? "scope " : "global scope",
3696 		scope ? ZSTR_VAL(scope->name) : ""
3697 	);
3698 }
3699 
3700 #if ZEND_INTENSIVE_DEBUGGING
3701 
3702 #define CHECK_SYMBOL_TABLES()													\
3703 	zend_hash_apply(&EG(symbol_table), zend_check_symbol);			\
3704 	if (&EG(symbol_table)!=EX(symbol_table)) {							\
3705 		zend_hash_apply(EX(symbol_table), zend_check_symbol);	\
3706 	}
3707 
zend_check_symbol(zval * pz)3708 static void zend_check_symbol(zval *pz)
3709 {
3710 	if (Z_TYPE_P(pz) == IS_INDIRECT) {
3711 		pz = Z_INDIRECT_P(pz);
3712 	}
3713 	if (Z_TYPE_P(pz) > 10) {
3714 		fprintf(stderr, "Warning!  %x has invalid type!\n", *pz);
3715 /* See http://support.microsoft.com/kb/190351 */
3716 #ifdef ZEND_WIN32
3717 		fflush(stderr);
3718 #endif
3719 	} else if (Z_TYPE_P(pz) == IS_ARRAY) {
3720 		zend_hash_apply(Z_ARRVAL_P(pz), zend_check_symbol);
3721 	} else if (Z_TYPE_P(pz) == IS_OBJECT) {
3722 		/* OBJ-TBI - doesn't support new object model! */
3723 		zend_hash_apply(Z_OBJPROP_P(pz), zend_check_symbol);
3724 	}
3725 }
3726 
3727 
3728 #else
3729 #define CHECK_SYMBOL_TABLES()
3730 #endif
3731 
execute_internal(zend_execute_data * execute_data,zval * return_value)3732 ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value)
3733 {
3734 	execute_data->func->internal_function.handler(execute_data, return_value);
3735 }
3736 
zend_clean_and_cache_symbol_table(zend_array * symbol_table)3737 ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{ */
3738 {
3739 	/* Clean before putting into the cache, since clean could call dtors,
3740 	 * which could use the cached hash. Also do this before the check for
3741 	 * available cache slots, as those may be used by a dtor as well. */
3742 	zend_symtable_clean(symbol_table);
3743 	if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
3744 		zend_array_destroy(symbol_table);
3745 	} else {
3746 		*(EG(symtable_cache_ptr)++) = symbol_table;
3747 	}
3748 }
3749 /* }}} */
3750 
i_free_compiled_variables(zend_execute_data * execute_data)3751 static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
3752 {
3753 	zval *cv = EX_VAR_NUM(0);
3754 	int count = EX(func)->op_array.last_var;
3755 	while (EXPECTED(count != 0)) {
3756 		i_zval_ptr_dtor(cv);
3757 		cv++;
3758 		count--;
3759 	}
3760 }
3761 /* }}} */
3762 
zend_free_compiled_variables(zend_execute_data * execute_data)3763 ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
3764 {
3765 	i_free_compiled_variables(execute_data);
3766 }
3767 /* }}} */
3768 
3769 #define ZEND_VM_INTERRUPT_CHECK() do { \
3770 		if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { \
3771 			ZEND_VM_INTERRUPT(); \
3772 		} \
3773 	} while (0)
3774 
3775 #define ZEND_VM_LOOP_INTERRUPT_CHECK() do { \
3776 		if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { \
3777 			ZEND_VM_LOOP_INTERRUPT(); \
3778 		} \
3779 	} while (0)
3780 
3781 /*
3782  * Stack Frame Layout (the whole stack frame is allocated at once)
3783  * ==================
3784  *
3785  *                             +========================================+
3786  * EG(current_execute_data) -> | zend_execute_data                      |
3787  *                             +----------------------------------------+
3788  *     EX_VAR_NUM(0) --------> | VAR[0] = ARG[1]                        |
3789  *                             | ...                                    |
3790  *                             | VAR[op_array->num_args-1] = ARG[N]     |
3791  *                             | ...                                    |
3792  *                             | VAR[op_array->last_var-1]              |
3793  *                             | VAR[op_array->last_var] = TMP[0]       |
3794  *                             | ...                                    |
3795  *                             | VAR[op_array->last_var+op_array->T-1]  |
3796  *                             | ARG[N+1] (extra_args)                  |
3797  *                             | ...                                    |
3798  *                             +----------------------------------------+
3799  */
3800 
3801 /* zend_copy_extra_args is used when the actually passed number of arguments
3802  * (EX_NUM_ARGS) is greater than what the function defined (op_array->num_args).
3803  *
3804  * The extra arguments will be copied into the call frame after all the compiled variables.
3805  *
3806  * If there are extra arguments copied, a flag "ZEND_CALL_FREE_EXTRA_ARGS" will be set
3807  * on the zend_execute_data, and when the executor leaves the function, the
3808  * args will be freed in zend_leave_helper.
3809  */
zend_copy_extra_args(EXECUTE_DATA_D)3810 static zend_never_inline void zend_copy_extra_args(EXECUTE_DATA_D)
3811 {
3812 	zend_op_array *op_array = &EX(func)->op_array;
3813 	uint32_t first_extra_arg = op_array->num_args;
3814 	uint32_t num_args = EX_NUM_ARGS();
3815 	zval *src;
3816 	size_t delta;
3817 	uint32_t count;
3818 	uint32_t type_flags = 0;
3819 
3820 	if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
3821 		/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
3822 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3823 		opline += first_extra_arg;
3824 #else
3825 		EX(opline) += first_extra_arg;
3826 #endif
3827 
3828 	}
3829 
3830 	/* move extra args into separate array after all CV and TMP vars */
3831 	src = EX_VAR_NUM(num_args - 1);
3832 	delta = op_array->last_var + op_array->T - first_extra_arg;
3833 	count = num_args - first_extra_arg;
3834 	if (EXPECTED(delta != 0)) {
3835 		delta *= sizeof(zval);
3836 		do {
3837 			type_flags |= Z_TYPE_INFO_P(src);
3838 			ZVAL_COPY_VALUE((zval*)(((char*)src) + delta), src);
3839 			ZVAL_UNDEF(src);
3840 			src--;
3841 		} while (--count);
3842 		if (Z_TYPE_INFO_REFCOUNTED(type_flags)) {
3843 			ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
3844 		}
3845 	} else {
3846 		do {
3847 			if (Z_REFCOUNTED_P(src)) {
3848 				ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
3849 				break;
3850 			}
3851 			src--;
3852 		} while (--count);
3853 	}
3854 }
3855 
zend_init_cvs(uint32_t first,uint32_t last EXECUTE_DATA_DC)3856 static zend_always_inline void zend_init_cvs(uint32_t first, uint32_t last EXECUTE_DATA_DC)
3857 {
3858 	if (EXPECTED(first < last)) {
3859 		uint32_t count = last - first;
3860 		zval *var = EX_VAR_NUM(first);
3861 
3862 		do {
3863 			ZVAL_UNDEF(var);
3864 			var++;
3865 		} while (--count);
3866 	}
3867 }
3868 
i_init_func_execute_data(zend_op_array * op_array,zval * return_value,bool may_be_trampoline EXECUTE_DATA_DC)3869 static zend_always_inline void i_init_func_execute_data(zend_op_array *op_array, zval *return_value, bool may_be_trampoline EXECUTE_DATA_DC) /* {{{ */
3870 {
3871 	uint32_t first_extra_arg, num_args;
3872 	ZEND_ASSERT(EX(func) == (zend_function*)op_array);
3873 
3874 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3875 	opline = op_array->opcodes;
3876 #else
3877 	EX(opline) = op_array->opcodes;
3878 #endif
3879 	EX(call) = NULL;
3880 	EX(return_value) = return_value;
3881 
3882 	/* Handle arguments */
3883 	first_extra_arg = op_array->num_args;
3884 	num_args = EX_NUM_ARGS();
3885 	if (UNEXPECTED(num_args > first_extra_arg)) {
3886 		if (!may_be_trampoline || EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
3887 			zend_copy_extra_args(EXECUTE_DATA_C);
3888 		}
3889 	} else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
3890 		/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
3891 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3892 		opline += num_args;
3893 #else
3894 		EX(opline) += num_args;
3895 #endif
3896 	}
3897 
3898 	/* Initialize CV variables (skip arguments) */
3899 	zend_init_cvs(num_args, op_array->last_var EXECUTE_DATA_CC);
3900 
3901 	EX(run_time_cache) = RUN_TIME_CACHE(op_array);
3902 
3903 	EG(current_execute_data) = execute_data;
3904 }
3905 /* }}} */
3906 
init_func_run_time_cache_i(zend_op_array * op_array)3907 static zend_always_inline void init_func_run_time_cache_i(zend_op_array *op_array) /* {{{ */
3908 {
3909 	void **run_time_cache;
3910 
3911 	ZEND_ASSERT(RUN_TIME_CACHE(op_array) == NULL);
3912 	run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
3913 	memset(run_time_cache, 0, op_array->cache_size);
3914 	ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
3915 }
3916 /* }}} */
3917 
init_func_run_time_cache(zend_op_array * op_array)3918 static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_array *op_array) /* {{{ */
3919 {
3920 	init_func_run_time_cache_i(op_array);
3921 }
3922 /* }}} */
3923 
zend_fetch_function(zend_string * name)3924 ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* {{{ */
3925 {
3926 	zval *zv = zend_hash_find(EG(function_table), name);
3927 
3928 	if (EXPECTED(zv != NULL)) {
3929 		zend_function *fbc = Z_FUNC_P(zv);
3930 
3931 		if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
3932 			init_func_run_time_cache_i(&fbc->op_array);
3933 		}
3934 		return fbc;
3935 	}
3936 	return NULL;
3937 } /* }}} */
3938 
zend_fetch_function_str(const char * name,size_t len)3939 ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */
3940 {
3941 	zval *zv = zend_hash_str_find(EG(function_table), name, len);
3942 
3943 	if (EXPECTED(zv != NULL)) {
3944 		zend_function *fbc = Z_FUNC_P(zv);
3945 
3946 		if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
3947 			init_func_run_time_cache_i(&fbc->op_array);
3948 		}
3949 		return fbc;
3950 	}
3951 	return NULL;
3952 } /* }}} */
3953 
zend_init_func_run_time_cache(zend_op_array * op_array)3954 ZEND_API void ZEND_FASTCALL zend_init_func_run_time_cache(zend_op_array *op_array) /* {{{ */
3955 {
3956 	if (!RUN_TIME_CACHE(op_array)) {
3957 		init_func_run_time_cache_i(op_array);
3958 	}
3959 } /* }}} */
3960 
i_init_code_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value)3961 static zend_always_inline void i_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
3962 {
3963 	ZEND_ASSERT(EX(func) == (zend_function*)op_array);
3964 
3965 	EX(opline) = op_array->opcodes;
3966 	EX(call) = NULL;
3967 	EX(return_value) = return_value;
3968 
3969 	if (op_array->last_var) {
3970 		zend_attach_symbol_table(execute_data);
3971 	}
3972 
3973 	if (!ZEND_MAP_PTR(op_array->run_time_cache)) {
3974 		void *ptr;
3975 
3976 		ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE);
3977 		ptr = emalloc(op_array->cache_size);
3978 		ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr);
3979 		memset(ptr, 0, op_array->cache_size);
3980 	}
3981 	EX(run_time_cache) = RUN_TIME_CACHE(op_array);
3982 
3983 	EG(current_execute_data) = execute_data;
3984 }
3985 /* }}} */
3986 
zend_init_func_execute_data(zend_execute_data * ex,zend_op_array * op_array,zval * return_value)3987 ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array *op_array, zval *return_value) /* {{{ */
3988 {
3989 #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3990 	zend_execute_data *orig_execute_data = execute_data;
3991 #endif
3992 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3993 	const zend_op *orig_opline = opline;
3994 #endif
3995 #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3996 	execute_data = ex;
3997 #else
3998 	zend_execute_data *execute_data = ex;
3999 #endif
4000 
4001 	EX(prev_execute_data) = EG(current_execute_data);
4002 	if (!RUN_TIME_CACHE(op_array)) {
4003 		init_func_run_time_cache(op_array);
4004 	}
4005 	i_init_func_execute_data(op_array, return_value, 1 EXECUTE_DATA_CC);
4006 
4007 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
4008 	EX(opline) = opline;
4009 	opline = orig_opline;
4010 #endif
4011 #if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
4012 	execute_data = orig_execute_data;
4013 #endif
4014 }
4015 /* }}} */
4016 
zend_init_code_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value)4017 ZEND_API void zend_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
4018 {
4019 	EX(prev_execute_data) = EG(current_execute_data);
4020 	i_init_code_execute_data(execute_data, op_array, return_value);
4021 }
4022 /* }}} */
4023 
zend_init_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value)4024 ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
4025 {
4026 	if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
4027 		zend_init_code_execute_data(execute_data, op_array, return_value);
4028 	} else {
4029 		zend_init_func_execute_data(execute_data, op_array, return_value);
4030 	}
4031 }
4032 /* }}} */
4033 
zend_vm_stack_copy_call_frame(zend_execute_data * call,uint32_t passed_args,uint32_t additional_args)4034 zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, uint32_t passed_args, uint32_t additional_args) /* {{{ */
4035 {
4036 	zend_execute_data *new_call;
4037 	int used_stack = (EG(vm_stack_top) - (zval*)call) + additional_args;
4038 
4039 	/* copy call frame into new stack segment */
4040 	new_call = zend_vm_stack_extend(used_stack * sizeof(zval));
4041 	*new_call = *call;
4042 	ZEND_ADD_CALL_FLAG(new_call, ZEND_CALL_ALLOCATED);
4043 
4044 	if (passed_args) {
4045 		zval *src = ZEND_CALL_ARG(call, 1);
4046 		zval *dst = ZEND_CALL_ARG(new_call, 1);
4047 		do {
4048 			ZVAL_COPY_VALUE(dst, src);
4049 			passed_args--;
4050 			src++;
4051 			dst++;
4052 		} while (passed_args);
4053 	}
4054 
4055 	/* delete old call_frame from previous stack segment */
4056 	EG(vm_stack)->prev->top = (zval*)call;
4057 
4058 	/* delete previous stack segment if it became empty */
4059 	if (UNEXPECTED(EG(vm_stack)->prev->top == ZEND_VM_STACK_ELEMENTS(EG(vm_stack)->prev))) {
4060 		zend_vm_stack r = EG(vm_stack)->prev;
4061 
4062 		EG(vm_stack)->prev = r->prev;
4063 		efree(r);
4064 	}
4065 
4066 	return new_call;
4067 }
4068 /* }}} */
4069 
zend_get_running_generator(EXECUTE_DATA_D)4070 static zend_always_inline zend_generator *zend_get_running_generator(EXECUTE_DATA_D) /* {{{ */
4071 {
4072 	/* The generator object is stored in EX(return_value) */
4073 	zend_generator *generator = (zend_generator *) EX(return_value);
4074 	/* However control may currently be delegated to another generator.
4075 	 * That's the one we're interested in. */
4076 	return generator;
4077 }
4078 /* }}} */
4079 
zend_unfinished_calls_gc(zend_execute_data * execute_data,zend_execute_data * call,uint32_t op_num,zend_get_gc_buffer * buf)4080 ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_execute_data *call, uint32_t op_num, zend_get_gc_buffer *buf) /* {{{ */
4081 {
4082 	zend_op *opline = EX(func)->op_array.opcodes + op_num;
4083 	int level;
4084 	int do_exit;
4085 	uint32_t num_args;
4086 
4087 	if (UNEXPECTED(opline->opcode == ZEND_INIT_FCALL ||
4088 		opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
4089 		opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
4090 		opline->opcode == ZEND_INIT_DYNAMIC_CALL ||
4091 		opline->opcode == ZEND_INIT_USER_CALL ||
4092 		opline->opcode == ZEND_INIT_METHOD_CALL ||
4093 		opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
4094 		opline->opcode == ZEND_NEW)) {
4095 		ZEND_ASSERT(op_num);
4096 		opline--;
4097 	}
4098 
4099 	do {
4100 		/* find the number of actually passed arguments */
4101 		level = 0;
4102 		do_exit = 0;
4103 		num_args = ZEND_CALL_NUM_ARGS(call);
4104 		do {
4105 			switch (opline->opcode) {
4106 				case ZEND_DO_FCALL:
4107 				case ZEND_DO_ICALL:
4108 				case ZEND_DO_UCALL:
4109 				case ZEND_DO_FCALL_BY_NAME:
4110 				case ZEND_CALLABLE_CONVERT:
4111 					level++;
4112 					break;
4113 				case ZEND_INIT_FCALL:
4114 				case ZEND_INIT_FCALL_BY_NAME:
4115 				case ZEND_INIT_NS_FCALL_BY_NAME:
4116 				case ZEND_INIT_DYNAMIC_CALL:
4117 				case ZEND_INIT_USER_CALL:
4118 				case ZEND_INIT_METHOD_CALL:
4119 				case ZEND_INIT_STATIC_METHOD_CALL:
4120 				case ZEND_NEW:
4121 					if (level == 0) {
4122 						num_args = 0;
4123 						do_exit = 1;
4124 					}
4125 					level--;
4126 					break;
4127 				case ZEND_SEND_VAL:
4128 				case ZEND_SEND_VAL_EX:
4129 				case ZEND_SEND_VAR:
4130 				case ZEND_SEND_VAR_EX:
4131 				case ZEND_SEND_FUNC_ARG:
4132 				case ZEND_SEND_REF:
4133 				case ZEND_SEND_VAR_NO_REF:
4134 				case ZEND_SEND_VAR_NO_REF_EX:
4135 				case ZEND_SEND_USER:
4136 					if (level == 0) {
4137 						/* For named args, the number of arguments is up to date. */
4138 						if (opline->op2_type != IS_CONST) {
4139 							num_args = opline->op2.num;
4140 						}
4141 						do_exit = 1;
4142 					}
4143 					break;
4144 				case ZEND_SEND_ARRAY:
4145 				case ZEND_SEND_UNPACK:
4146 				case ZEND_CHECK_UNDEF_ARGS:
4147 					if (level == 0) {
4148 						do_exit = 1;
4149 					}
4150 					break;
4151 			}
4152 			if (!do_exit) {
4153 				opline--;
4154 			}
4155 		} while (!do_exit);
4156 		if (call->prev_execute_data) {
4157 			/* skip current call region */
4158 			level = 0;
4159 			do_exit = 0;
4160 			do {
4161 				switch (opline->opcode) {
4162 					case ZEND_DO_FCALL:
4163 					case ZEND_DO_ICALL:
4164 					case ZEND_DO_UCALL:
4165 					case ZEND_DO_FCALL_BY_NAME:
4166 					case ZEND_CALLABLE_CONVERT:
4167 						level++;
4168 						break;
4169 					case ZEND_INIT_FCALL:
4170 					case ZEND_INIT_FCALL_BY_NAME:
4171 					case ZEND_INIT_NS_FCALL_BY_NAME:
4172 					case ZEND_INIT_DYNAMIC_CALL:
4173 					case ZEND_INIT_USER_CALL:
4174 					case ZEND_INIT_METHOD_CALL:
4175 					case ZEND_INIT_STATIC_METHOD_CALL:
4176 					case ZEND_NEW:
4177 						if (level == 0) {
4178 							do_exit = 1;
4179 						}
4180 						level--;
4181 						break;
4182 				}
4183 				opline--;
4184 			} while (!do_exit);
4185 		}
4186 
4187 		if (EXPECTED(num_args > 0)) {
4188 			zval *p = ZEND_CALL_ARG(call, 1);
4189 			do {
4190 				zend_get_gc_buffer_add_zval(buf, p);
4191 				p++;
4192 			} while (--num_args);
4193 		}
4194 		if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
4195 			zend_get_gc_buffer_add_obj(buf, Z_OBJ(call->This));
4196 		}
4197 		if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
4198 			zval *val;
4199 			ZEND_HASH_FOREACH_VAL(call->extra_named_params, val) {
4200 				zend_get_gc_buffer_add_zval(buf, val);
4201 			} ZEND_HASH_FOREACH_END();
4202 		}
4203 		if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
4204 			zend_get_gc_buffer_add_obj(buf, ZEND_CLOSURE_OBJECT(call->func));
4205 		}
4206 
4207 		call = call->prev_execute_data;
4208 	} while (call);
4209 }
4210 /* }}} */
4211 
cleanup_unfinished_calls(zend_execute_data * execute_data,uint32_t op_num)4212 static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */
4213 {
4214 	if (UNEXPECTED(EX(call))) {
4215 		zend_execute_data *call = EX(call);
4216 		zend_op *opline = EX(func)->op_array.opcodes + op_num;
4217 		int level;
4218 		int do_exit;
4219 
4220 		if (UNEXPECTED(opline->opcode == ZEND_INIT_FCALL ||
4221 			opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
4222 			opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
4223 			opline->opcode == ZEND_INIT_DYNAMIC_CALL ||
4224 			opline->opcode == ZEND_INIT_USER_CALL ||
4225 			opline->opcode == ZEND_INIT_METHOD_CALL ||
4226 			opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
4227 			opline->opcode == ZEND_NEW)) {
4228 			ZEND_ASSERT(op_num);
4229 			opline--;
4230 		}
4231 
4232 		do {
4233 			/* If the exception was thrown during a function call there might be
4234 			 * arguments pushed to the stack that have to be dtor'ed. */
4235 
4236 			/* find the number of actually passed arguments */
4237 			level = 0;
4238 			do_exit = 0;
4239 			do {
4240 				switch (opline->opcode) {
4241 					case ZEND_DO_FCALL:
4242 					case ZEND_DO_ICALL:
4243 					case ZEND_DO_UCALL:
4244 					case ZEND_DO_FCALL_BY_NAME:
4245 					case ZEND_CALLABLE_CONVERT:
4246 						level++;
4247 						break;
4248 					case ZEND_INIT_FCALL:
4249 					case ZEND_INIT_FCALL_BY_NAME:
4250 					case ZEND_INIT_NS_FCALL_BY_NAME:
4251 					case ZEND_INIT_DYNAMIC_CALL:
4252 					case ZEND_INIT_USER_CALL:
4253 					case ZEND_INIT_METHOD_CALL:
4254 					case ZEND_INIT_STATIC_METHOD_CALL:
4255 					case ZEND_NEW:
4256 						if (level == 0) {
4257 							ZEND_CALL_NUM_ARGS(call) = 0;
4258 							do_exit = 1;
4259 						}
4260 						level--;
4261 						break;
4262 					case ZEND_SEND_VAL:
4263 					case ZEND_SEND_VAL_EX:
4264 					case ZEND_SEND_VAR:
4265 					case ZEND_SEND_VAR_EX:
4266 					case ZEND_SEND_FUNC_ARG:
4267 					case ZEND_SEND_REF:
4268 					case ZEND_SEND_VAR_NO_REF:
4269 					case ZEND_SEND_VAR_NO_REF_EX:
4270 					case ZEND_SEND_USER:
4271 						if (level == 0) {
4272 							/* For named args, the number of arguments is up to date. */
4273 							if (opline->op2_type != IS_CONST) {
4274 								ZEND_CALL_NUM_ARGS(call) = opline->op2.num;
4275 							}
4276 							do_exit = 1;
4277 						}
4278 						break;
4279 					case ZEND_SEND_ARRAY:
4280 					case ZEND_SEND_UNPACK:
4281 					case ZEND_CHECK_UNDEF_ARGS:
4282 						if (level == 0) {
4283 							do_exit = 1;
4284 						}
4285 						break;
4286 				}
4287 				if (!do_exit) {
4288 					opline--;
4289 				}
4290 			} while (!do_exit);
4291 			if (call->prev_execute_data) {
4292 				/* skip current call region */
4293 				level = 0;
4294 				do_exit = 0;
4295 				do {
4296 					switch (opline->opcode) {
4297 						case ZEND_DO_FCALL:
4298 						case ZEND_DO_ICALL:
4299 						case ZEND_DO_UCALL:
4300 						case ZEND_DO_FCALL_BY_NAME:
4301 						case ZEND_CALLABLE_CONVERT:
4302 							level++;
4303 							break;
4304 						case ZEND_INIT_FCALL:
4305 						case ZEND_INIT_FCALL_BY_NAME:
4306 						case ZEND_INIT_NS_FCALL_BY_NAME:
4307 						case ZEND_INIT_DYNAMIC_CALL:
4308 						case ZEND_INIT_USER_CALL:
4309 						case ZEND_INIT_METHOD_CALL:
4310 						case ZEND_INIT_STATIC_METHOD_CALL:
4311 						case ZEND_NEW:
4312 							if (level == 0) {
4313 								do_exit = 1;
4314 							}
4315 							level--;
4316 							break;
4317 					}
4318 					opline--;
4319 				} while (!do_exit);
4320 			}
4321 
4322 			zend_vm_stack_free_args(EX(call));
4323 
4324 			if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
4325 				OBJ_RELEASE(Z_OBJ(call->This));
4326 			}
4327 			if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
4328 				zend_free_extra_named_params(call->extra_named_params);
4329 			}
4330 			if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
4331 				zend_object_release(ZEND_CLOSURE_OBJECT(call->func));
4332 			} else if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
4333 				zend_string_release_ex(call->func->common.function_name, 0);
4334 				zend_free_trampoline(call->func);
4335 			}
4336 
4337 			EX(call) = call->prev_execute_data;
4338 			zend_vm_stack_free_call_frame(call);
4339 			call = EX(call);
4340 		} while (call);
4341 	}
4342 }
4343 /* }}} */
4344 
find_live_range(const zend_op_array * op_array,uint32_t op_num,uint32_t var_num)4345 static const zend_live_range *find_live_range(const zend_op_array *op_array, uint32_t op_num, uint32_t var_num) /* {{{ */
4346 {
4347 	int i;
4348 	for (i = 0; i < op_array->last_live_range; i++) {
4349 		const zend_live_range *range = &op_array->live_range[i];
4350 		if (op_num >= range->start && op_num < range->end
4351 				&& var_num == (range->var & ~ZEND_LIVE_MASK)) {
4352 			return range;
4353 		}
4354 	}
4355 	return NULL;
4356 }
4357 /* }}} */
4358 
cleanup_live_vars(zend_execute_data * execute_data,uint32_t op_num,uint32_t catch_op_num)4359 static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
4360 {
4361 	int i;
4362 
4363 	for (i = 0; i < EX(func)->op_array.last_live_range; i++) {
4364 		const zend_live_range *range = &EX(func)->op_array.live_range[i];
4365 		if (range->start > op_num) {
4366 			/* further blocks will not be relevant... */
4367 			break;
4368 		} else if (op_num < range->end) {
4369 			if (!catch_op_num || catch_op_num >= range->end) {
4370 				uint32_t kind = range->var & ZEND_LIVE_MASK;
4371 				uint32_t var_num = range->var & ~ZEND_LIVE_MASK;
4372 				zval *var = EX_VAR(var_num);
4373 
4374 				if (kind == ZEND_LIVE_TMPVAR) {
4375 					zval_ptr_dtor_nogc(var);
4376 				} else if (kind == ZEND_LIVE_NEW) {
4377 					zend_object *obj;
4378 					ZEND_ASSERT(Z_TYPE_P(var) == IS_OBJECT);
4379 					obj = Z_OBJ_P(var);
4380 					zend_object_store_ctor_failed(obj);
4381 					OBJ_RELEASE(obj);
4382 				} else if (kind == ZEND_LIVE_LOOP) {
4383 					if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
4384 						zend_hash_iterator_del(Z_FE_ITER_P(var));
4385 					}
4386 					zval_ptr_dtor_nogc(var);
4387 				} else if (kind == ZEND_LIVE_ROPE) {
4388 					zend_string **rope = (zend_string **)var;
4389 					zend_op *last = EX(func)->op_array.opcodes + op_num;
4390 					while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT)
4391 							|| last->result.var != var_num) {
4392 						ZEND_ASSERT(last >= EX(func)->op_array.opcodes);
4393 						last--;
4394 					}
4395 					if (last->opcode == ZEND_ROPE_INIT) {
4396 						zend_string_release_ex(*rope, 0);
4397 					} else {
4398 						int j = last->extended_value;
4399 						do {
4400 							zend_string_release_ex(rope[j], 0);
4401 						} while (j--);
4402 					}
4403 				} else if (kind == ZEND_LIVE_SILENCE) {
4404 					/* restore previous error_reporting value */
4405 					if (E_HAS_ONLY_FATAL_ERRORS(EG(error_reporting))
4406 							&& !E_HAS_ONLY_FATAL_ERRORS(Z_LVAL_P(var))) {
4407 						EG(error_reporting) = Z_LVAL_P(var);
4408 					}
4409 				}
4410 			}
4411 		}
4412 	}
4413 }
4414 /* }}} */
4415 
zend_cleanup_unfinished_execution(zend_execute_data * execute_data,uint32_t op_num,uint32_t catch_op_num)4416 ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) {
4417 	cleanup_unfinished_calls(execute_data, op_num);
4418 	cleanup_live_vars(execute_data, op_num, catch_op_num);
4419 }
4420 
zend_unfinished_execution_gc(zend_execute_data * execute_data,zend_execute_data * call,zend_get_gc_buffer * gc_buffer)4421 ZEND_API ZEND_ATTRIBUTE_DEPRECATED HashTable *zend_unfinished_execution_gc(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer)
4422 {
4423 	bool suspended_by_yield = false;
4424 
4425 	if (Z_TYPE_INFO(EX(This)) & ZEND_CALL_GENERATOR) {
4426 		ZEND_ASSERT(EX(return_value));
4427 
4428 		/* The generator object is stored in EX(return_value) */
4429 		zend_generator *generator = (zend_generator*) EX(return_value);
4430 		ZEND_ASSERT(execute_data == generator->execute_data);
4431 
4432 		suspended_by_yield = !(generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING);
4433 	}
4434 
4435 	return zend_unfinished_execution_gc_ex(execute_data, call, gc_buffer, suspended_by_yield);
4436 }
4437 
zend_unfinished_execution_gc_ex(zend_execute_data * execute_data,zend_execute_data * call,zend_get_gc_buffer * gc_buffer,bool suspended_by_yield)4438 ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer, bool suspended_by_yield)
4439 {
4440 	if (!EX(func)) {
4441 		return NULL;
4442 	}
4443 
4444 	if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) {
4445 		zend_get_gc_buffer_add_obj(gc_buffer, Z_OBJ(execute_data->This));
4446 	}
4447 
4448 	if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
4449 		zend_get_gc_buffer_add_obj(gc_buffer, ZEND_CLOSURE_OBJECT(EX(func)));
4450 	}
4451 
4452 	if (!ZEND_USER_CODE(EX(func)->common.type)) {
4453 		ZEND_ASSERT(!(EX_CALL_INFO() & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)));
4454 		return NULL;
4455 	}
4456 
4457 	zend_op_array *op_array = &EX(func)->op_array;
4458 
4459 	if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
4460 		uint32_t i, num_cvs = EX(func)->op_array.last_var;
4461 		for (i = 0; i < num_cvs; i++) {
4462 			zend_get_gc_buffer_add_zval(gc_buffer, EX_VAR_NUM(i));
4463 		}
4464 	}
4465 
4466 	if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) {
4467 		zval *zv = EX_VAR_NUM(op_array->last_var + op_array->T);
4468 		zval *end = zv + (EX_NUM_ARGS() - op_array->num_args);
4469 		while (zv != end) {
4470 			zend_get_gc_buffer_add_zval(gc_buffer, zv++);
4471 		}
4472 	}
4473 
4474 	if (EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
4475 		zval extra_named_params;
4476 		ZVAL_ARR(&extra_named_params, EX(extra_named_params));
4477 		zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params);
4478 	}
4479 
4480 	if (call) {
4481 		uint32_t op_num;
4482 		if (UNEXPECTED(execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION)) {
4483 			op_num = EG(opline_before_exception) - op_array->opcodes;
4484 		} else {
4485 			op_num = execute_data->opline - op_array->opcodes;
4486 		}
4487 		ZEND_ASSERT(op_num < op_array->last);
4488 		if (suspended_by_yield) {
4489 			/* When the execution was suspended by yield, EX(opline) points to
4490 			 * next opline to execute. Otherwise, it points to the opline that
4491 			 * suspended execution. */
4492 			op_num--;
4493 			ZEND_ASSERT(EX(func)->op_array.opcodes[op_num].opcode == ZEND_YIELD
4494 				|| EX(func)->op_array.opcodes[op_num].opcode == ZEND_YIELD_FROM);
4495 		}
4496 		zend_unfinished_calls_gc(execute_data, call, op_num, gc_buffer);
4497 	}
4498 
4499 	if (execute_data->opline != op_array->opcodes) {
4500 		uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
4501 		for (i = 0; i < op_array->last_live_range; i++) {
4502 			const zend_live_range *range = &op_array->live_range[i];
4503 			if (range->start > op_num) {
4504 				break;
4505 			} else if (op_num < range->end) {
4506 				uint32_t kind = range->var & ZEND_LIVE_MASK;
4507 				uint32_t var_num = range->var & ~ZEND_LIVE_MASK;
4508 				zval *var = EX_VAR(var_num);
4509 				if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
4510 					zend_get_gc_buffer_add_zval(gc_buffer, var);
4511 				}
4512 			}
4513 		}
4514 	}
4515 
4516 	if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
4517 		return execute_data->symbol_table;
4518 	} else {
4519 		return NULL;
4520 	}
4521 }
4522 
4523 #if ZEND_VM_SPEC
zend_swap_operands(zend_op * op)4524 static void zend_swap_operands(zend_op *op) /* {{{ */
4525 {
4526 	znode_op     tmp;
4527 	zend_uchar   tmp_type;
4528 
4529 	tmp          = op->op1;
4530 	tmp_type     = op->op1_type;
4531 	op->op1      = op->op2;
4532 	op->op1_type = op->op2_type;
4533 	op->op2      = tmp;
4534 	op->op2_type = tmp_type;
4535 }
4536 /* }}} */
4537 #endif
4538 
zend_init_dynamic_call_string(zend_string * function,uint32_t num_args)4539 static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
4540 {
4541 	zend_function *fbc;
4542 	zval *func;
4543 	zend_class_entry *called_scope;
4544 	zend_string *lcname;
4545 	const char *colon;
4546 
4547 	if ((colon = zend_memrchr(ZSTR_VAL(function), ':', ZSTR_LEN(function))) != NULL &&
4548 		colon > ZSTR_VAL(function) &&
4549 		*(colon-1) == ':'
4550 	) {
4551 		zend_string *mname;
4552 		size_t cname_length = colon - ZSTR_VAL(function) - 1;
4553 		size_t mname_length = ZSTR_LEN(function) - cname_length - (sizeof("::") - 1);
4554 
4555 		lcname = zend_string_init(ZSTR_VAL(function), cname_length, 0);
4556 
4557 		called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
4558 		if (UNEXPECTED(called_scope == NULL)) {
4559 			zend_string_release_ex(lcname, 0);
4560 			return NULL;
4561 		}
4562 
4563 		mname = zend_string_init(ZSTR_VAL(function) + (cname_length + sizeof("::") - 1), mname_length, 0);
4564 
4565 		if (called_scope->get_static_method) {
4566 			fbc = called_scope->get_static_method(called_scope, mname);
4567 		} else {
4568 			fbc = zend_std_get_static_method(called_scope, mname, NULL);
4569 		}
4570 		if (UNEXPECTED(fbc == NULL)) {
4571 			if (EXPECTED(!EG(exception))) {
4572 				zend_undefined_method(called_scope, mname);
4573 			}
4574 			zend_string_release_ex(lcname, 0);
4575 			zend_string_release_ex(mname, 0);
4576 			return NULL;
4577 		}
4578 
4579 		zend_string_release_ex(lcname, 0);
4580 		zend_string_release_ex(mname, 0);
4581 
4582 		if (UNEXPECTED(!(fbc->common.fn_flags & ZEND_ACC_STATIC))) {
4583 			zend_non_static_method_call(fbc);
4584 			if (fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
4585 				zend_string_release_ex(fbc->common.function_name, 0);
4586 				zend_free_trampoline(fbc);
4587 			}
4588 			return NULL;
4589 		}
4590 		if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4591 			init_func_run_time_cache(&fbc->op_array);
4592 		}
4593 	} else {
4594 		if (ZSTR_VAL(function)[0] == '\\') {
4595 			lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
4596 			zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
4597 		} else {
4598 			lcname = zend_string_tolower(function);
4599 		}
4600 		if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
4601 			zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
4602 			zend_string_release_ex(lcname, 0);
4603 			return NULL;
4604 		}
4605 		zend_string_release_ex(lcname, 0);
4606 
4607 		fbc = Z_FUNC_P(func);
4608 		if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4609 			init_func_run_time_cache(&fbc->op_array);
4610 		}
4611 		called_scope = NULL;
4612 	}
4613 
4614 	return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC,
4615 		fbc, num_args, called_scope);
4616 }
4617 /* }}} */
4618 
zend_init_dynamic_call_object(zend_object * function,uint32_t num_args)4619 static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zend_object *function, uint32_t num_args) /* {{{ */
4620 {
4621 	zend_function *fbc;
4622 	void *object_or_called_scope;
4623 	zend_class_entry *called_scope;
4624 	zend_object *object;
4625 	uint32_t call_info;
4626 
4627 	if (EXPECTED(function->handlers->get_closure) &&
4628 	    EXPECTED(function->handlers->get_closure(function, &called_scope, &fbc, &object, 0) == SUCCESS)) {
4629 
4630 		object_or_called_scope = called_scope;
4631 		if (EXPECTED(fbc->common.fn_flags & ZEND_ACC_CLOSURE)) {
4632 			/* Delay closure destruction until its invocation */
4633 			GC_ADDREF(ZEND_CLOSURE_OBJECT(fbc));
4634 			ZEND_ASSERT(ZEND_ACC_FAKE_CLOSURE == ZEND_CALL_FAKE_CLOSURE);
4635 			call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
4636 				(fbc->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
4637 			if (object) {
4638 				call_info |= ZEND_CALL_HAS_THIS;
4639 				object_or_called_scope = object;
4640 			}
4641 		} else {
4642 			call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
4643 			if (object) {
4644 				call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS;
4645 				GC_ADDREF(object); /* For $this pointer */
4646 				object_or_called_scope = object;
4647 			}
4648 		}
4649 	} else {
4650 		zend_throw_error(NULL, "Object of type %s is not callable", ZSTR_VAL(function->ce->name));
4651 		return NULL;
4652 	}
4653 
4654 	if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4655 		init_func_run_time_cache(&fbc->op_array);
4656 	}
4657 
4658 	return zend_vm_stack_push_call_frame(call_info,
4659 		fbc, num_args, object_or_called_scope);
4660 }
4661 /* }}} */
4662 
zend_init_dynamic_call_array(zend_array * function,uint32_t num_args)4663 static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_array *function, uint32_t num_args) /* {{{ */
4664 {
4665 	zend_function *fbc;
4666 	void *object_or_called_scope;
4667 	uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
4668 
4669 	if (zend_hash_num_elements(function) == 2) {
4670 		zval *obj;
4671 		zval *method;
4672 		obj = zend_hash_index_find(function, 0);
4673 		method = zend_hash_index_find(function, 1);
4674 
4675 		if (UNEXPECTED(!obj) || UNEXPECTED(!method)) {
4676 			zend_throw_error(NULL, "Array callback has to contain indices 0 and 1");
4677 			return NULL;
4678 		}
4679 
4680 		ZVAL_DEREF(obj);
4681 		if (UNEXPECTED(Z_TYPE_P(obj) != IS_STRING) && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT)) {
4682 			zend_throw_error(NULL, "First array member is not a valid class name or object");
4683 			return NULL;
4684 		}
4685 
4686 		ZVAL_DEREF(method);
4687 		if (UNEXPECTED(Z_TYPE_P(method) != IS_STRING)) {
4688 			zend_throw_error(NULL, "Second array member is not a valid method");
4689 			return NULL;
4690 		}
4691 
4692 		if (Z_TYPE_P(obj) == IS_STRING) {
4693 			zend_class_entry *called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
4694 
4695 			if (UNEXPECTED(called_scope == NULL)) {
4696 				return NULL;
4697 			}
4698 
4699 			if (called_scope->get_static_method) {
4700 				fbc = called_scope->get_static_method(called_scope, Z_STR_P(method));
4701 			} else {
4702 				fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL);
4703 			}
4704 			if (UNEXPECTED(fbc == NULL)) {
4705 				if (EXPECTED(!EG(exception))) {
4706 					zend_undefined_method(called_scope, Z_STR_P(method));
4707 				}
4708 				return NULL;
4709 			}
4710 			if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
4711 				zend_non_static_method_call(fbc);
4712 				if (fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
4713 					zend_string_release_ex(fbc->common.function_name, 0);
4714 					zend_free_trampoline(fbc);
4715 				}
4716 				return NULL;
4717 			}
4718 			object_or_called_scope = called_scope;
4719 		} else {
4720 			zend_object *object = Z_OBJ_P(obj);
4721 
4722 			fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL);
4723 			if (UNEXPECTED(fbc == NULL)) {
4724 				if (EXPECTED(!EG(exception))) {
4725 					zend_undefined_method(object->ce, Z_STR_P(method));
4726 				}
4727 				return NULL;
4728 			}
4729 
4730 			if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
4731 				object_or_called_scope = object->ce;
4732 			} else {
4733 				call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS;
4734 				GC_ADDREF(object); /* For $this pointer */
4735 				object_or_called_scope = object;
4736 			}
4737 		}
4738 	} else {
4739 		zend_throw_error(NULL, "Array callback must have exactly two elements");
4740 		return NULL;
4741 	}
4742 
4743 	if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4744 		init_func_run_time_cache(&fbc->op_array);
4745 	}
4746 
4747 	return zend_vm_stack_push_call_frame(call_info,
4748 		fbc, num_args, object_or_called_scope);
4749 }
4750 /* }}} */
4751 
4752 #define ZEND_FAKE_OP_ARRAY ((zend_op_array*)(zend_intptr_t)-1)
4753 
zend_include_or_eval(zval * inc_filename_zv,int type)4754 static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval *inc_filename_zv, int type) /* {{{ */
4755 {
4756 	zend_op_array *new_op_array = NULL;
4757 	zend_string *tmp_inc_filename;
4758 	zend_string *inc_filename = zval_try_get_tmp_string(inc_filename_zv, &tmp_inc_filename);
4759 	if (UNEXPECTED(!inc_filename)) {
4760 		return NULL;
4761 	}
4762 
4763 	switch (type) {
4764 		case ZEND_INCLUDE_ONCE:
4765 		case ZEND_REQUIRE_ONCE: {
4766 				zend_file_handle file_handle;
4767 				zend_string *resolved_path;
4768 
4769 				resolved_path = zend_resolve_path(inc_filename);
4770 				if (EXPECTED(resolved_path)) {
4771 					if (zend_hash_exists(&EG(included_files), resolved_path)) {
4772 						new_op_array = ZEND_FAKE_OP_ARRAY;
4773 						zend_string_release_ex(resolved_path, 0);
4774 						break;
4775 					}
4776 				} else if (UNEXPECTED(EG(exception))) {
4777 					break;
4778 				} else if (UNEXPECTED(strlen(ZSTR_VAL(inc_filename)) != ZSTR_LEN(inc_filename))) {
4779 					zend_message_dispatcher(
4780 						(type == ZEND_INCLUDE_ONCE) ?
4781 							ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
4782 							ZSTR_VAL(inc_filename));
4783 					break;
4784 				} else {
4785 					resolved_path = zend_string_copy(inc_filename);
4786 				}
4787 
4788 				zend_stream_init_filename_ex(&file_handle, resolved_path);
4789 				if (SUCCESS == zend_stream_open(&file_handle)) {
4790 
4791 					if (!file_handle.opened_path) {
4792 						file_handle.opened_path = zend_string_copy(resolved_path);
4793 					}
4794 
4795 					if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) {
4796 						new_op_array = zend_compile_file(&file_handle, (type==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE));
4797 					} else {
4798 						new_op_array = ZEND_FAKE_OP_ARRAY;
4799 					}
4800 				} else if (!EG(exception)) {
4801 					zend_message_dispatcher(
4802 						(type == ZEND_INCLUDE_ONCE) ?
4803 							ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
4804 							ZSTR_VAL(inc_filename));
4805 				}
4806 				zend_destroy_file_handle(&file_handle);
4807 				zend_string_release_ex(resolved_path, 0);
4808 			}
4809 			break;
4810 		case ZEND_INCLUDE:
4811 		case ZEND_REQUIRE:
4812 			if (UNEXPECTED(strlen(ZSTR_VAL(inc_filename)) != ZSTR_LEN(inc_filename))) {
4813 				zend_message_dispatcher(
4814 					(type == ZEND_INCLUDE) ?
4815 						ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
4816 						ZSTR_VAL(inc_filename));
4817 				break;
4818 			}
4819 			new_op_array = compile_filename(type, inc_filename);
4820 			break;
4821 		case ZEND_EVAL: {
4822 				char *eval_desc = zend_make_compiled_string_description("eval()'d code");
4823 				new_op_array = zend_compile_string(inc_filename, eval_desc, ZEND_COMPILE_POSITION_AFTER_OPEN_TAG);
4824 				efree(eval_desc);
4825 			}
4826 			break;
4827 		EMPTY_SWITCH_DEFAULT_CASE()
4828 	}
4829 
4830 	zend_tmp_string_release(tmp_inc_filename);
4831 	return new_op_array;
4832 }
4833 /* }}} */
4834 
zend_fe_reset_iterator(zval * array_ptr,int by_ref OPLINE_DC EXECUTE_DATA_DC)4835 static zend_never_inline bool ZEND_FASTCALL zend_fe_reset_iterator(zval *array_ptr, int by_ref OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
4836 {
4837 	zend_class_entry *ce = Z_OBJCE_P(array_ptr);
4838 	zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, by_ref);
4839 	bool is_empty;
4840 
4841 	if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
4842 		if (iter) {
4843 			OBJ_RELEASE(&iter->std);
4844 		}
4845 		if (!EG(exception)) {
4846 			zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ZSTR_VAL(ce->name));
4847 		}
4848 		ZVAL_UNDEF(EX_VAR(opline->result.var));
4849 		return 1;
4850 	}
4851 
4852 	iter->index = 0;
4853 	if (iter->funcs->rewind) {
4854 		iter->funcs->rewind(iter);
4855 		if (UNEXPECTED(EG(exception) != NULL)) {
4856 			OBJ_RELEASE(&iter->std);
4857 			ZVAL_UNDEF(EX_VAR(opline->result.var));
4858 			return 1;
4859 		}
4860 	}
4861 
4862 	is_empty = iter->funcs->valid(iter) != SUCCESS;
4863 
4864 	if (UNEXPECTED(EG(exception) != NULL)) {
4865 		OBJ_RELEASE(&iter->std);
4866 		ZVAL_UNDEF(EX_VAR(opline->result.var));
4867 		return 1;
4868 	}
4869 	iter->index = -1; /* will be set to 0 before using next handler */
4870 
4871 	ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
4872 	Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
4873 
4874 	return is_empty;
4875 }
4876 /* }}} */
4877 
_zend_quick_get_constant(const zval * key,uint32_t flags,bool check_defined_only OPLINE_DC EXECUTE_DATA_DC)4878 static zend_always_inline zend_result _zend_quick_get_constant(
4879 		const zval *key, uint32_t flags, bool check_defined_only OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
4880 {
4881 	zval *zv;
4882 	zend_constant *c = NULL;
4883 
4884 	/* null/true/false are resolved during compilation, so don't check for them here. */
4885 	zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
4886 	if (zv) {
4887 		c = (zend_constant*)Z_PTR_P(zv);
4888 	} else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
4889 		key++;
4890 		zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
4891 		if (zv) {
4892 			c = (zend_constant*)Z_PTR_P(zv);
4893 		}
4894 	}
4895 
4896 	if (!c) {
4897 		if (!check_defined_only) {
4898 			zend_throw_error(NULL, "Undefined constant \"%s\"", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
4899 			ZVAL_UNDEF(EX_VAR(opline->result.var));
4900 		}
4901 		return FAILURE;
4902 	}
4903 
4904 	if (!check_defined_only) {
4905 		ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
4906 		if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) {
4907 			zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(c->name));
4908 			return SUCCESS;
4909 		}
4910 	}
4911 
4912 	CACHE_PTR(opline->extended_value, c);
4913 	return SUCCESS;
4914 }
4915 /* }}} */
4916 
zend_quick_get_constant(const zval * key,uint32_t flags OPLINE_DC EXECUTE_DATA_DC)4917 static zend_never_inline void ZEND_FASTCALL zend_quick_get_constant(
4918 		const zval *key, uint32_t flags OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
4919 {
4920 	_zend_quick_get_constant(key, flags, 0 OPLINE_CC EXECUTE_DATA_CC);
4921 } /* }}} */
4922 
zend_quick_check_constant(const zval * key OPLINE_DC EXECUTE_DATA_DC)4923 static zend_never_inline zend_result ZEND_FASTCALL zend_quick_check_constant(
4924 		const zval *key OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
4925 {
4926 	return _zend_quick_get_constant(key, 0, 1 OPLINE_CC EXECUTE_DATA_CC);
4927 } /* }}} */
4928 
zend_get_arg_offset_by_name(zend_function * fbc,zend_string * arg_name,void ** cache_slot)4929 static zend_always_inline uint32_t zend_get_arg_offset_by_name(
4930 		zend_function *fbc, zend_string *arg_name, void **cache_slot) {
4931 	if (EXPECTED(*cache_slot == fbc)) {
4932 		return *(uintptr_t *)(cache_slot + 1);
4933 	}
4934 
4935 	// TODO: Use a hash table?
4936 	uint32_t num_args = fbc->common.num_args;
4937 	if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)
4938 			|| EXPECTED(fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
4939 		for (uint32_t i = 0; i < num_args; i++) {
4940 			zend_arg_info *arg_info = &fbc->op_array.arg_info[i];
4941 			if (zend_string_equals(arg_name, arg_info->name)) {
4942 				*cache_slot = fbc;
4943 				*(uintptr_t *)(cache_slot + 1) = i;
4944 				return i;
4945 			}
4946 		}
4947 	} else {
4948 		for (uint32_t i = 0; i < num_args; i++) {
4949 			zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i];
4950 			size_t len = strlen(arg_info->name);
4951 			if (zend_string_equals_cstr(arg_name, arg_info->name, len)) {
4952 				*cache_slot = fbc;
4953 				*(uintptr_t *)(cache_slot + 1) = i;
4954 				return i;
4955 			}
4956 		}
4957 	}
4958 
4959 	if (fbc->common.fn_flags & ZEND_ACC_VARIADIC) {
4960 		*cache_slot = fbc;
4961 		*(uintptr_t *)(cache_slot + 1) = fbc->common.num_args;
4962 		return fbc->common.num_args;
4963 	}
4964 
4965 	return (uint32_t) -1;
4966 }
4967 
zend_handle_named_arg(zend_execute_data ** call_ptr,zend_string * arg_name,uint32_t * arg_num_ptr,void ** cache_slot)4968 zval * ZEND_FASTCALL zend_handle_named_arg(
4969 		zend_execute_data **call_ptr, zend_string *arg_name,
4970 		uint32_t *arg_num_ptr, void **cache_slot) {
4971 	zend_execute_data *call = *call_ptr;
4972 	zend_function *fbc = call->func;
4973 	uint32_t arg_offset = zend_get_arg_offset_by_name(fbc, arg_name, cache_slot);
4974 	if (UNEXPECTED(arg_offset == (uint32_t) -1)) {
4975 		zend_throw_error(NULL, "Unknown named parameter $%s", ZSTR_VAL(arg_name));
4976 		return NULL;
4977 	}
4978 
4979 	zval *arg;
4980 	if (UNEXPECTED(arg_offset == fbc->common.num_args)) {
4981 		/* Unknown named parameter that will be collected into a variadic. */
4982 		if (!(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
4983 			ZEND_ADD_CALL_FLAG(call, ZEND_CALL_HAS_EXTRA_NAMED_PARAMS);
4984 			call->extra_named_params = zend_new_array(0);
4985 		}
4986 
4987 		arg = zend_hash_add_empty_element(call->extra_named_params, arg_name);
4988 		if (!arg) {
4989 			zend_throw_error(NULL, "Named parameter $%s overwrites previous argument",
4990 				ZSTR_VAL(arg_name));
4991 			return NULL;
4992 		}
4993 		*arg_num_ptr = arg_offset + 1;
4994 		return arg;
4995 	}
4996 
4997 	uint32_t current_num_args = ZEND_CALL_NUM_ARGS(call);
4998 	// TODO: We may wish to optimize the arg_offset == current_num_args case,
4999 	// which is probably common (if the named parameters are in order of declaration).
5000 	if (arg_offset >= current_num_args) {
5001 		uint32_t new_num_args = arg_offset + 1;
5002 		ZEND_CALL_NUM_ARGS(call) = new_num_args;
5003 
5004 		uint32_t num_extra_args = new_num_args - current_num_args;
5005 		zend_vm_stack_extend_call_frame(call_ptr, current_num_args, num_extra_args);
5006 		call = *call_ptr;
5007 
5008 		arg = ZEND_CALL_VAR_NUM(call, arg_offset);
5009 		if (num_extra_args > 1) {
5010 			zval *zv = ZEND_CALL_VAR_NUM(call, current_num_args);
5011 			do {
5012 				ZVAL_UNDEF(zv);
5013 				zv++;
5014 			} while (zv != arg);
5015 			ZEND_ADD_CALL_FLAG(call, ZEND_CALL_MAY_HAVE_UNDEF);
5016 		}
5017 	} else {
5018 		arg = ZEND_CALL_VAR_NUM(call, arg_offset);
5019 		if (UNEXPECTED(!Z_ISUNDEF_P(arg))) {
5020 			zend_throw_error(NULL, "Named parameter $%s overwrites previous argument",
5021 				ZSTR_VAL(arg_name));
5022 			return NULL;
5023 		}
5024 	}
5025 
5026 	*arg_num_ptr = arg_offset + 1;
5027 	return arg;
5028 }
5029 
start_fake_frame(zend_execute_data * call,const zend_op * opline)5030 static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_op *opline) {
5031 	zend_execute_data *old_prev_execute_data = call->prev_execute_data;
5032 	call->prev_execute_data = EG(current_execute_data);
5033 	call->opline = opline;
5034 	EG(current_execute_data) = call;
5035 	return old_prev_execute_data;
5036 }
5037 
end_fake_frame(zend_execute_data * call,zend_execute_data * old_prev_execute_data)5038 static void end_fake_frame(zend_execute_data *call, zend_execute_data *old_prev_execute_data) {
5039 	zend_execute_data *prev_execute_data = call->prev_execute_data;
5040 	EG(current_execute_data) = prev_execute_data;
5041 	call->prev_execute_data = old_prev_execute_data;
5042 	if (UNEXPECTED(EG(exception)) && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
5043 		zend_rethrow_exception(prev_execute_data);
5044 	}
5045 }
5046 
zend_handle_undef_args(zend_execute_data * call)5047 ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call) {
5048 	zend_function *fbc = call->func;
5049 	if (fbc->type == ZEND_USER_FUNCTION) {
5050 		zend_op_array *op_array = &fbc->op_array;
5051 		uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
5052 		for (uint32_t i = 0; i < num_args; i++) {
5053 			zval *arg = ZEND_CALL_VAR_NUM(call, i);
5054 			if (!Z_ISUNDEF_P(arg)) {
5055 				continue;
5056 			}
5057 
5058 			zend_op *opline = &op_array->opcodes[i];
5059 			if (EXPECTED(opline->opcode == ZEND_RECV_INIT)) {
5060 				zval *default_value = RT_CONSTANT(opline, opline->op2);
5061 				if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
5062 					if (UNEXPECTED(!RUN_TIME_CACHE(op_array))) {
5063 						init_func_run_time_cache(op_array);
5064 					}
5065 
5066 					void *run_time_cache = RUN_TIME_CACHE(op_array);
5067 					zval *cache_val =
5068 						(zval *) ((char *) run_time_cache + Z_CACHE_SLOT_P(default_value));
5069 
5070 					if (Z_TYPE_P(cache_val) != IS_UNDEF) {
5071 						/* We keep in cache only not refcounted values */
5072 						ZVAL_COPY_VALUE(arg, cache_val);
5073 					} else {
5074 						/* Update constant inside a temporary zval, to make sure the CONSTANT_AST
5075 						 * value is not accessible through back traces. */
5076 						zval tmp;
5077 						ZVAL_COPY(&tmp, default_value);
5078 						zend_execute_data *old = start_fake_frame(call, opline);
5079 						zend_result ret = zval_update_constant_ex(&tmp, fbc->op_array.scope);
5080 						end_fake_frame(call, old);
5081 						if (UNEXPECTED(ret == FAILURE)) {
5082 							zval_ptr_dtor_nogc(&tmp);
5083 							return FAILURE;
5084 						}
5085 						ZVAL_COPY_VALUE(arg, &tmp);
5086 						if (!Z_REFCOUNTED(tmp)) {
5087 							ZVAL_COPY_VALUE(cache_val, &tmp);
5088 						}
5089 					}
5090 				} else {
5091 					ZVAL_COPY(arg, default_value);
5092 				}
5093 			} else {
5094 				ZEND_ASSERT(opline->opcode == ZEND_RECV);
5095 				zend_execute_data *old = start_fake_frame(call, opline);
5096 				zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
5097 				end_fake_frame(call, old);
5098 				return FAILURE;
5099 			}
5100 		}
5101 
5102 		return SUCCESS;
5103 	} else {
5104 		if (fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO) {
5105 			/* Magic function, let it deal with it. */
5106 			return SUCCESS;
5107 		}
5108 
5109 		uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
5110 		for (uint32_t i = 0; i < num_args; i++) {
5111 			zval *arg = ZEND_CALL_VAR_NUM(call, i);
5112 			if (!Z_ISUNDEF_P(arg)) {
5113 				continue;
5114 			}
5115 
5116 			zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i];
5117 			if (i < fbc->common.required_num_args) {
5118 				zend_execute_data *old = start_fake_frame(call, NULL);
5119 				zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
5120 				end_fake_frame(call, old);
5121 				return FAILURE;
5122 			}
5123 
5124 			zval default_value;
5125 			if (zend_get_default_from_internal_arg_info(&default_value, arg_info) == FAILURE) {
5126 				zend_execute_data *old = start_fake_frame(call, NULL);
5127 				zend_argument_error(zend_ce_argument_count_error, i + 1,
5128 					"must be passed explicitly, because the default value is not known");
5129 				end_fake_frame(call, old);
5130 				return FAILURE;
5131 			}
5132 
5133 			if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
5134 				zend_execute_data *old = start_fake_frame(call, NULL);
5135 				zend_result ret = zval_update_constant_ex(&default_value, fbc->common.scope);
5136 				end_fake_frame(call, old);
5137 				if (ret == FAILURE) {
5138 					return FAILURE;
5139 				}
5140 			}
5141 
5142 			ZVAL_COPY_VALUE(arg, &default_value);
5143 			if (ZEND_ARG_SEND_MODE(arg_info) & ZEND_SEND_BY_REF) {
5144 				ZVAL_NEW_REF(arg, arg);
5145 			}
5146 		}
5147 	}
5148 
5149 	return SUCCESS;
5150 }
5151 
zend_free_extra_named_params(zend_array * extra_named_params)5152 ZEND_API void ZEND_FASTCALL zend_free_extra_named_params(zend_array *extra_named_params)
5153 {
5154 	/* Extra named params may be shared. */
5155 	zend_array_release(extra_named_params);
5156 }
5157 
5158 #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
5159 /* Special versions of functions that sets EX(opline) before calling zend_vm_stack_extend() */
_zend_vm_stack_push_call_frame_ex(uint32_t used_stack,uint32_t call_info,zend_function * func,uint32_t num_args,void * object_or_called_scope)5160 static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope) /* {{{ */
5161 {
5162 	zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top);
5163 
5164 	ZEND_ASSERT_VM_STACK_GLOBAL;
5165 
5166 	if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
5167 		EX(opline) = opline; /* this is the only difference */
5168 		call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
5169 		ZEND_ASSERT_VM_STACK_GLOBAL;
5170 		zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, object_or_called_scope);
5171 		return call;
5172 	} else {
5173 		EG(vm_stack_top) = (zval*)((char*)call + used_stack);
5174 		zend_vm_init_call_frame(call, call_info, func, num_args, object_or_called_scope);
5175 		return call;
5176 	}
5177 } /* }}} */
5178 
_zend_vm_stack_push_call_frame(uint32_t call_info,zend_function * func,uint32_t num_args,void * object_or_called_scope)5179 static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope) /* {{{ */
5180 {
5181 	uint32_t used_stack = zend_vm_calc_used_stack(num_args, func);
5182 
5183 	return _zend_vm_stack_push_call_frame_ex(used_stack, call_info,
5184 		func, num_args, object_or_called_scope);
5185 } /* }}} */
5186 #else
5187 # define _zend_vm_stack_push_call_frame_ex zend_vm_stack_push_call_frame_ex
5188 # define _zend_vm_stack_push_call_frame    zend_vm_stack_push_call_frame
5189 #endif
5190 
5191 #ifdef ZEND_VM_TRACE_HANDLERS
5192 # include "zend_vm_trace_handlers.h"
5193 #elif defined(ZEND_VM_TRACE_LINES)
5194 # include "zend_vm_trace_lines.h"
5195 #elif defined(ZEND_VM_TRACE_MAP)
5196 # include "zend_vm_trace_map.h"
5197 #endif
5198 
5199 #define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
5200 	CHECK_SYMBOL_TABLES() \
5201 	if (check_exception) { \
5202 		OPLINE = EX(opline) + (skip); \
5203 	} else { \
5204 		ZEND_ASSERT(!EG(exception)); \
5205 		OPLINE = opline + (skip); \
5206 	} \
5207 	ZEND_VM_CONTINUE()
5208 
5209 #define ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION() \
5210 	ZEND_VM_NEXT_OPCODE_EX(1, 1)
5211 
5212 #define ZEND_VM_NEXT_OPCODE() \
5213 	ZEND_VM_NEXT_OPCODE_EX(0, 1)
5214 
5215 #define ZEND_VM_SET_NEXT_OPCODE(new_op) \
5216 	CHECK_SYMBOL_TABLES() \
5217 	OPLINE = new_op
5218 
5219 #define ZEND_VM_SET_OPCODE(new_op) \
5220 	CHECK_SYMBOL_TABLES() \
5221 	OPLINE = new_op; \
5222 	ZEND_VM_INTERRUPT_CHECK()
5223 
5224 #define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
5225 	ZEND_VM_SET_OPCODE(ZEND_OFFSET_TO_OPLINE(opline, offset))
5226 
5227 #define ZEND_VM_JMP_EX(new_op, check_exception) do { \
5228 		if (check_exception && UNEXPECTED(EG(exception))) { \
5229 			HANDLE_EXCEPTION(); \
5230 		} \
5231 		ZEND_VM_SET_OPCODE(new_op); \
5232 		ZEND_VM_CONTINUE(); \
5233 	} while (0)
5234 
5235 #define ZEND_VM_JMP(new_op) \
5236 	ZEND_VM_JMP_EX(new_op, 1)
5237 
5238 #define ZEND_VM_INC_OPCODE() \
5239 	OPLINE++
5240 
5241 
5242 #define ZEND_VM_REPEATABLE_OPCODE \
5243 	do {
5244 #define ZEND_VM_REPEAT_OPCODE(_opcode) \
5245 	} while (UNEXPECTED((++opline)->opcode == _opcode)); \
5246 	OPLINE = opline; \
5247 	ZEND_VM_CONTINUE()
5248 #define ZEND_VM_SMART_BRANCH(_result, _check) do { \
5249 		if ((_check) && UNEXPECTED(EG(exception))) { \
5250 			OPLINE = EX(opline); \
5251 		} else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \
5252 			if (_result) { \
5253 				ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5254 			} else { \
5255 				ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5256 			} \
5257 		} else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR))) { \
5258 			if (!(_result)) { \
5259 				ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5260 			} else { \
5261 				ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5262 			} \
5263 		} else { \
5264 			ZVAL_BOOL(EX_VAR(opline->result.var), _result); \
5265 			ZEND_VM_SET_NEXT_OPCODE(opline + 1); \
5266 		} \
5267 		ZEND_VM_CONTINUE(); \
5268 	} while (0)
5269 #define ZEND_VM_SMART_BRANCH_JMPZ(_result, _check) do { \
5270 		if ((_check) && UNEXPECTED(EG(exception))) { \
5271 			OPLINE = EX(opline); \
5272 		} else if (_result) { \
5273 			ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5274 		} else { \
5275 			ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5276 		} \
5277 		ZEND_VM_CONTINUE(); \
5278 	} while (0)
5279 #define ZEND_VM_SMART_BRANCH_JMPNZ(_result, _check) do { \
5280 		if ((_check) && UNEXPECTED(EG(exception))) { \
5281 			OPLINE = EX(opline); \
5282 		} else if (!(_result)) { \
5283 			ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5284 		} else { \
5285 			ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5286 		} \
5287 		ZEND_VM_CONTINUE(); \
5288 	} while (0)
5289 #define ZEND_VM_SMART_BRANCH_NONE(_result, _check) do { \
5290 		ZVAL_BOOL(EX_VAR(opline->result.var), _result); \
5291 		ZEND_VM_NEXT_OPCODE_EX(_check, 1); \
5292 		ZEND_VM_CONTINUE(); \
5293 	} while (0)
5294 #define ZEND_VM_SMART_BRANCH_TRUE() do { \
5295 		if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR))) { \
5296 			ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5297 		} else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \
5298 			ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5299 		} else { \
5300 			ZVAL_TRUE(EX_VAR(opline->result.var)); \
5301 			ZEND_VM_SET_NEXT_OPCODE(opline + 1); \
5302 		} \
5303 		ZEND_VM_CONTINUE(); \
5304 	} while (0)
5305 #define ZEND_VM_SMART_BRANCH_TRUE_JMPZ() do { \
5306 		ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5307 		ZEND_VM_CONTINUE(); \
5308 	} while (0)
5309 #define ZEND_VM_SMART_BRANCH_TRUE_JMPNZ() do { \
5310 		ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5311 		ZEND_VM_CONTINUE(); \
5312 	} while (0)
5313 #define ZEND_VM_SMART_BRANCH_TRUE_NONE() do { \
5314 		ZVAL_TRUE(EX_VAR(opline->result.var)); \
5315 		ZEND_VM_NEXT_OPCODE(); \
5316 	} while (0)
5317 #define ZEND_VM_SMART_BRANCH_FALSE() do { \
5318 		if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR))) { \
5319 			ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5320 		} else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \
5321 			ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5322 		} else { \
5323 			ZVAL_FALSE(EX_VAR(opline->result.var)); \
5324 			ZEND_VM_SET_NEXT_OPCODE(opline + 1); \
5325 		} \
5326 		ZEND_VM_CONTINUE(); \
5327 	} while (0)
5328 #define ZEND_VM_SMART_BRANCH_FALSE_JMPZ() do { \
5329 		ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
5330 		ZEND_VM_CONTINUE(); \
5331 	} while (0)
5332 #define ZEND_VM_SMART_BRANCH_FALSE_JMPNZ() do { \
5333 		ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
5334 		ZEND_VM_CONTINUE(); \
5335 	} while (0)
5336 #define ZEND_VM_SMART_BRANCH_FALSE_NONE() do { \
5337 		ZVAL_FALSE(EX_VAR(opline->result.var)); \
5338 		ZEND_VM_NEXT_OPCODE(); \
5339 	} while (0)
5340 
5341 #ifdef __GNUC__
5342 # define ZEND_VM_GUARD(name) __asm__("#" #name)
5343 #else
5344 # define ZEND_VM_GUARD(name)
5345 #endif
5346 
5347 #define UNDEF_RESULT() do { \
5348 		if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { \
5349 			ZVAL_UNDEF(EX_VAR(opline->result.var)); \
5350 		} \
5351 	} while (0)
5352 
5353 /* This callback disables optimization of "vm_stack_data" variable in VM */
5354 ZEND_API void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data) = NULL;
5355 
5356 #include "zend_vm_execute.h"
5357 
zend_set_user_opcode_handler(zend_uchar opcode,user_opcode_handler_t handler)5358 ZEND_API zend_result zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
5359 {
5360 	if (opcode != ZEND_USER_OPCODE) {
5361 		if (handler == NULL) {
5362 			/* restore the original handler */
5363 			zend_user_opcodes[opcode] = opcode;
5364 		} else {
5365 			zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
5366 		}
5367 		zend_user_opcode_handlers[opcode] = handler;
5368 		return SUCCESS;
5369 	}
5370 	return FAILURE;
5371 }
5372 
zend_get_user_opcode_handler(zend_uchar opcode)5373 ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
5374 {
5375 	return zend_user_opcode_handlers[opcode];
5376 }
5377 
zend_get_zval_ptr(const zend_op * opline,int op_type,const znode_op * node,const zend_execute_data * execute_data)5378 ZEND_API zval *zend_get_zval_ptr(const zend_op *opline, int op_type, const znode_op *node, const zend_execute_data *execute_data)
5379 {
5380 	zval *ret;
5381 
5382 	switch (op_type) {
5383 		case IS_CONST:
5384 			ret = RT_CONSTANT(opline, *node);
5385 			break;
5386 		case IS_TMP_VAR:
5387 		case IS_VAR:
5388 		case IS_CV:
5389 			ret = EX_VAR(node->var);
5390 			break;
5391 		default:
5392 			ret = NULL;
5393 			break;
5394 	}
5395 	return ret;
5396 }
5397