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