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