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