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