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