1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2017 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@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 | Dmitry Stogov <dmitry@zend.com> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id$ */
22
23 #define ZEND_INTENSIVE_DEBUGGING 0
24
25 #include <stdio.h>
26 #include <signal.h>
27
28 #include "zend.h"
29 #include "zend_compile.h"
30 #include "zend_execute.h"
31 #include "zend_API.h"
32 #include "zend_ptr_stack.h"
33 #include "zend_constants.h"
34 #include "zend_extensions.h"
35 #include "zend_ini.h"
36 #include "zend_exceptions.h"
37 #include "zend_interfaces.h"
38 #include "zend_closures.h"
39 #include "zend_generators.h"
40 #include "zend_vm.h"
41 #include "zend_dtrace.h"
42 #include "zend_inheritance.h"
43
44 /* Virtual current working directory support */
45 #include "zend_virtual_cwd.h"
46
47 #define _CONST_CODE 0
48 #define _TMP_CODE 1
49 #define _VAR_CODE 2
50 #define _UNUSED_CODE 3
51 #define _CV_CODE 4
52
53 typedef int (ZEND_FASTCALL *incdec_t)(zval *);
54
55 #define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type)
56 #define get_zval_ptr_deref(op_type, node, ex, should_free, type) _get_zval_ptr_deref(op_type, node, ex, should_free, type)
57 #define get_zval_ptr_r(op_type, node, ex, should_free) _get_zval_ptr_r(op_type, node, ex, should_free)
58 #define get_zval_ptr_r_deref(op_type, node, ex, should_free) _get_zval_ptr_r_deref(op_type, node, ex, should_free)
59 #define get_zval_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_undef(op_type, node, ex, should_free, type)
60 #define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type)
61 #define get_zval_ptr_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type)
62 #define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type)
63 #define get_obj_zval_ptr_undef(op_type, node, ex, should_free, type) _get_obj_zval_ptr_undef(op_type, node, ex, should_free, type)
64 #define get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type)
65
66 /* Prototypes */
67 static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array);
68 static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array);
69 static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array);
70
71 #define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
72
ZEND_FUNCTION(pass)73 static ZEND_FUNCTION(pass)
74 {
75 }
76
77 static const zend_internal_function zend_pass_function = {
78 ZEND_INTERNAL_FUNCTION, /* type */
79 {0, 0, 0}, /* arg_flags */
80 0, /* fn_flags */
81 NULL, /* name */
82 NULL, /* scope */
83 NULL, /* prototype */
84 0, /* num_args */
85 0, /* required_num_args */
86 NULL, /* arg_info */
87 ZEND_FN(pass), /* handler */
88 NULL /* module */
89 };
90
91 #undef zval_ptr_dtor
92 #define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC)
93
94 #define READY_TO_DESTROY(zv) \
95 (UNEXPECTED(zv) && Z_REFCOUNTED_P(zv) && Z_REFCOUNT_P(zv) == 1)
96
97 #define EXTRACT_ZVAL_PTR(zv, check_null) do { \
98 zval *__zv = (zv); \
99 if (EXPECTED(Z_TYPE_P(__zv) == IS_INDIRECT)) { \
100 if (!(check_null) || \
101 EXPECTED(Z_INDIRECT_P(__zv))) { \
102 ZVAL_COPY(__zv, Z_INDIRECT_P(__zv)); \
103 } \
104 } \
105 } while (0)
106
107 #define FREE_OP(should_free) \
108 if (should_free) { \
109 zval_ptr_dtor_nogc(should_free); \
110 }
111
112 #define FREE_UNFETCHED_OP(type, var) \
113 if ((type) & (IS_TMP_VAR|IS_VAR)) { \
114 zval_ptr_dtor_nogc(EX_VAR(var)); \
115 }
116
117 #define FREE_OP_VAR_PTR(should_free) \
118 if (should_free) { \
119 zval_ptr_dtor_nogc(should_free); \
120 }
121
122 /* End of zend_execute_locks.h */
123
124 #define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
125
126 #define CTOR_CALL_BIT 0x1
127 #define CTOR_USED_BIT 0x2
128
129 #define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
130 #define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
131
132 #define ENCODE_CTOR(ce, used) \
133 ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
134 #define DECODE_CTOR(ce) \
135 ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
136
137 #define ZEND_VM_MAIN_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
138 #define ZEND_VM_GENERATOR_STACK_PAGE_SLOTS (256)
139
140 #define ZEND_VM_STACK_PAGE_SLOTS(gen) ((gen) ? ZEND_VM_GENERATOR_STACK_PAGE_SLOTS : ZEND_VM_MAIN_STACK_PAGE_SLOTS)
141
142 #define ZEND_VM_STACK_PAGE_SIZE(gen) (ZEND_VM_STACK_PAGE_SLOTS(gen) * sizeof(zval))
143
144 #define ZEND_VM_STACK_FREE_PAGE_SIZE(gen) \
145 ((ZEND_VM_STACK_PAGE_SLOTS(gen) - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval))
146
147 #define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(gen, size) \
148 (((size) + ZEND_VM_STACK_HEADER_SLOTS * sizeof(zval) \
149 + (ZEND_VM_STACK_PAGE_SIZE(gen) - 1)) & ~(ZEND_VM_STACK_PAGE_SIZE(gen) - 1))
150
zend_vm_stack_new_page(size_t size,zend_vm_stack prev)151 static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
152 zend_vm_stack page = (zend_vm_stack)emalloc(size);
153
154 page->top = ZEND_VM_STACK_ELEMETS(page);
155 page->end = (zval*)((char*)page + size);
156 page->prev = prev;
157 return page;
158 }
159
zend_vm_stack_init(void)160 ZEND_API void zend_vm_stack_init(void)
161 {
162 EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE(0 /* main stack */), NULL);
163 EG(vm_stack)->top++;
164 EG(vm_stack_top) = EG(vm_stack)->top;
165 EG(vm_stack_end) = EG(vm_stack)->end;
166 }
167
zend_vm_stack_destroy(void)168 ZEND_API void zend_vm_stack_destroy(void)
169 {
170 zend_vm_stack stack = EG(vm_stack);
171
172 while (stack != NULL) {
173 zend_vm_stack p = stack->prev;
174 efree(stack);
175 stack = p;
176 }
177 }
178
zend_vm_stack_extend(size_t size)179 ZEND_API void* zend_vm_stack_extend(size_t size)
180 {
181 zend_vm_stack stack;
182 void *ptr;
183
184 stack = EG(vm_stack);
185 stack->top = EG(vm_stack_top);
186 EG(vm_stack) = stack = zend_vm_stack_new_page(
187 EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE(0)) ?
188 ZEND_VM_STACK_PAGE_SIZE(0) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(0, size),
189 stack);
190 ptr = stack->top;
191 EG(vm_stack_top) = (void*)(((char*)ptr) + size);
192 EG(vm_stack_end) = stack->end;
193 return ptr;
194 }
195
zend_get_compiled_variable_value(const zend_execute_data * execute_data,uint32_t var)196 ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data, uint32_t var)
197 {
198 return EX_VAR(var);
199 }
200
_get_zval_ptr_tmp(uint32_t var,const zend_execute_data * execute_data,zend_free_op * should_free)201 static zend_always_inline zval *_get_zval_ptr_tmp(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
202 {
203 zval *ret = EX_VAR(var);
204 *should_free = ret;
205
206 ZEND_ASSERT(Z_TYPE_P(ret) != IS_REFERENCE);
207
208 return ret;
209 }
210
_get_zval_ptr_var(uint32_t var,const zend_execute_data * execute_data,zend_free_op * should_free)211 static zend_always_inline zval *_get_zval_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
212 {
213 zval *ret = EX_VAR(var);
214
215 *should_free = ret;
216 return ret;
217 }
218
_get_zval_ptr_var_deref(uint32_t var,const zend_execute_data * execute_data,zend_free_op * should_free)219 static zend_always_inline zval *_get_zval_ptr_var_deref(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
220 {
221 zval *ret = EX_VAR(var);
222
223 *should_free = ret;
224 ZVAL_DEREF(ret);
225 return ret;
226 }
227
zval_undefined_cv(uint32_t var,const zend_execute_data * execute_data)228 static zend_never_inline ZEND_COLD void zval_undefined_cv(uint32_t var, const zend_execute_data *execute_data)
229 {
230 zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var));
231
232 zend_error(E_NOTICE, "Undefined variable: %s", ZSTR_VAL(cv));
233 }
234
_get_zval_cv_lookup(zval * ptr,uint32_t var,int type,const zend_execute_data * execute_data)235 static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, uint32_t var, int type, const zend_execute_data *execute_data)
236 {
237 switch (type) {
238 case BP_VAR_R:
239 case BP_VAR_UNSET:
240 zval_undefined_cv(var, execute_data);
241 /* break missing intentionally */
242 case BP_VAR_IS:
243 ptr = &EG(uninitialized_zval);
244 break;
245 case BP_VAR_RW:
246 zval_undefined_cv(var, execute_data);
247 /* break missing intentionally */
248 case BP_VAR_W:
249 ZVAL_NULL(ptr);
250 break;
251 }
252 return ptr;
253 }
254
_get_zval_cv_lookup_BP_VAR_R(zval * ptr,uint32_t var,const zend_execute_data * execute_data)255 static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
256 {
257 zval_undefined_cv(var, execute_data);
258 return &EG(uninitialized_zval);
259 }
260
_get_zval_cv_lookup_BP_VAR_UNSET(zval * ptr,uint32_t var,const zend_execute_data * execute_data)261 static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
262 {
263 zval_undefined_cv(var, execute_data);
264 return &EG(uninitialized_zval);
265 }
266
_get_zval_cv_lookup_BP_VAR_RW(zval * ptr,uint32_t var,const zend_execute_data * execute_data)267 static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
268 {
269 ZVAL_NULL(ptr);
270 zval_undefined_cv(var, execute_data);
271 return ptr;
272 }
273
_get_zval_cv_lookup_BP_VAR_W(zval * ptr,uint32_t var,const zend_execute_data * execute_data)274 static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_W(zval *ptr, uint32_t var, const zend_execute_data *execute_data)
275 {
276 ZVAL_NULL(ptr);
277 return ptr;
278 }
279
_get_zval_ptr_cv(const zend_execute_data * execute_data,uint32_t var,int type)280 static zend_always_inline zval *_get_zval_ptr_cv(const zend_execute_data *execute_data, uint32_t var, int type)
281 {
282 zval *ret = EX_VAR(var);
283
284 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
285 return _get_zval_cv_lookup(ret, var, type, execute_data);
286 }
287 return ret;
288 }
289
_get_zval_ptr_cv_undef(const zend_execute_data * execute_data,uint32_t var)290 static zend_always_inline zval *_get_zval_ptr_cv_undef(const zend_execute_data *execute_data, uint32_t var)
291 {
292 return EX_VAR(var);
293 }
294
_get_zval_ptr_cv_deref(const zend_execute_data * execute_data,uint32_t var,int type)295 static zend_always_inline zval *_get_zval_ptr_cv_deref(const zend_execute_data *execute_data, uint32_t var, int type)
296 {
297 zval *ret = EX_VAR(var);
298
299 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
300 return _get_zval_cv_lookup(ret, var, type, execute_data);
301 }
302 ZVAL_DEREF(ret);
303 return ret;
304 }
305
_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data * execute_data,uint32_t var)306 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, uint32_t var)
307 {
308 zval *ret = EX_VAR(var);
309
310 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
311 return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data);
312 }
313 return ret;
314 }
315
_get_zval_ptr_cv_deref_BP_VAR_R(const zend_execute_data * execute_data,uint32_t var)316 static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_R(const zend_execute_data *execute_data, uint32_t var)
317 {
318 zval *ret = EX_VAR(var);
319
320 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
321 return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data);
322 }
323 ZVAL_DEREF(ret);
324 return ret;
325 }
326
_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data * execute_data,uint32_t var)327 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var)
328 {
329 zval *ret = EX_VAR(var);
330
331 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
332 return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data);
333 }
334 return ret;
335 }
336
_get_zval_ptr_cv_deref_BP_VAR_UNSET(const zend_execute_data * execute_data,uint32_t var)337 static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var)
338 {
339 zval *ret = EX_VAR(var);
340
341 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
342 return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data);
343 }
344 ZVAL_DEREF(ret);
345 return ret;
346 }
347
_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data * execute_data,uint32_t var)348 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, uint32_t var)
349 {
350 zval *ret = EX_VAR(var);
351
352 return ret;
353 }
354
_get_zval_ptr_cv_deref_BP_VAR_IS(const zend_execute_data * execute_data,uint32_t var)355 static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_IS(const zend_execute_data *execute_data, uint32_t var)
356 {
357 zval *ret = EX_VAR(var);
358
359 ZVAL_DEREF(ret);
360 return ret;
361 }
362
_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data * execute_data,uint32_t var)363 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var)
364 {
365 zval *ret = EX_VAR(var);
366
367 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
368 return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data);
369 }
370 return ret;
371 }
372
_get_zval_ptr_cv_deref_BP_VAR_RW(const zend_execute_data * execute_data,uint32_t var)373 static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var)
374 {
375 zval *ret = EX_VAR(var);
376
377 if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
378 return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data);
379 }
380 ZVAL_DEREF(ret);
381 return ret;
382 }
383
_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data * execute_data,uint32_t var)384 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
385 {
386 zval *ret = EX_VAR(var);
387
388 if (Z_TYPE_P(ret) == IS_UNDEF) {
389 return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data);
390 }
391 return ret;
392 }
393
_get_zval_ptr_cv_undef_BP_VAR_W(const zend_execute_data * execute_data,uint32_t var)394 static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
395 {
396 return EX_VAR(var);
397 }
398
_get_zval_ptr_cv_undef_BP_VAR_RW(const zend_execute_data * execute_data,uint32_t var)399 static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_RW(const zend_execute_data *execute_data, uint32_t var)
400 {
401 return EX_VAR(var);
402 }
403
_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data * execute_data,uint32_t var)404 static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
405 {
406 zval *ret = EX_VAR(var);
407
408 if (Z_TYPE_P(ret) == IS_UNDEF) {
409 return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data);
410 }
411 ZVAL_DEREF(ret);
412 return ret;
413 }
414
_get_zval_ptr(int op_type,znode_op node,const zend_execute_data * execute_data,zend_free_op * should_free,int type)415 static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
416 {
417 if (op_type & (IS_TMP_VAR|IS_VAR)) {
418 if (op_type == IS_TMP_VAR) {
419 return _get_zval_ptr_tmp(node.var, execute_data, should_free);
420 } else {
421 ZEND_ASSERT(op_type == IS_VAR);
422 return _get_zval_ptr_var(node.var, execute_data, should_free);
423 }
424 } else {
425 *should_free = NULL;
426 if (op_type == IS_CONST) {
427 return EX_CONSTANT(node);
428 } else if (op_type == IS_CV) {
429 return _get_zval_ptr_cv(execute_data, node.var, type);
430 } else {
431 return NULL;
432 }
433 }
434 }
435
_get_zval_ptr_r(int op_type,znode_op node,const zend_execute_data * execute_data,zend_free_op * should_free)436 static zend_always_inline zval *_get_zval_ptr_r(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free)
437 {
438 if (op_type & (IS_TMP_VAR|IS_VAR)) {
439 if (op_type == IS_TMP_VAR) {
440 return _get_zval_ptr_tmp(node.var, execute_data, should_free);
441 } else {
442 ZEND_ASSERT(op_type == IS_VAR);
443 return _get_zval_ptr_var(node.var, execute_data, should_free);
444 }
445 } else {
446 *should_free = NULL;
447 if (op_type == IS_CONST) {
448 return EX_CONSTANT(node);
449 } else if (op_type == IS_CV) {
450 return _get_zval_ptr_cv_BP_VAR_R(execute_data, node.var);
451 } else {
452 return NULL;
453 }
454 }
455 }
456
_get_zval_ptr_deref(int op_type,znode_op node,const zend_execute_data * execute_data,zend_free_op * should_free,int type)457 static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
458 {
459 if (op_type & (IS_TMP_VAR|IS_VAR)) {
460 if (op_type == IS_TMP_VAR) {
461 return _get_zval_ptr_tmp(node.var, execute_data, should_free);
462 } else {
463 ZEND_ASSERT(op_type == IS_VAR);
464 return _get_zval_ptr_var_deref(node.var, execute_data, should_free);
465 }
466 } else {
467 *should_free = NULL;
468 if (op_type == IS_CONST) {
469 return EX_CONSTANT(node);
470 } else if (op_type == IS_CV) {
471 return _get_zval_ptr_cv_deref(execute_data, node.var, type);
472 } else {
473 return NULL;
474 }
475 }
476 }
477
_get_zval_ptr_r_deref(int op_type,znode_op node,const zend_execute_data * execute_data,zend_free_op * should_free)478 static zend_always_inline zval *_get_zval_ptr_r_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free)
479 {
480 if (op_type & (IS_TMP_VAR|IS_VAR)) {
481 if (op_type == IS_TMP_VAR) {
482 return _get_zval_ptr_tmp(node.var, execute_data, should_free);
483 } else {
484 ZEND_ASSERT(op_type == IS_VAR);
485 return _get_zval_ptr_var_deref(node.var, execute_data, should_free);
486 }
487 } else {
488 *should_free = NULL;
489 if (op_type == IS_CONST) {
490 return EX_CONSTANT(node);
491 } else if (op_type == IS_CV) {
492 return _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, node.var);
493 } else {
494 return NULL;
495 }
496 }
497 }
498
_get_zval_ptr_undef(int op_type,znode_op node,const zend_execute_data * execute_data,zend_free_op * should_free,int type)499 static zend_always_inline zval *_get_zval_ptr_undef(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
500 {
501 if (op_type & (IS_TMP_VAR|IS_VAR)) {
502 if (op_type == IS_TMP_VAR) {
503 return _get_zval_ptr_tmp(node.var, execute_data, should_free);
504 } else {
505 ZEND_ASSERT(op_type == IS_VAR);
506 return _get_zval_ptr_var(node.var, execute_data, should_free);
507 }
508 } else {
509 *should_free = NULL;
510 if (op_type == IS_CONST) {
511 return EX_CONSTANT(node);
512 } else if (op_type == IS_CV) {
513 return _get_zval_ptr_cv_undef(execute_data, node.var);
514 } else {
515 return NULL;
516 }
517 }
518 }
519
_get_zval_ptr_ptr_var(uint32_t var,const zend_execute_data * execute_data,zend_free_op * should_free)520 static zend_always_inline zval *_get_zval_ptr_ptr_var(uint32_t var, const zend_execute_data *execute_data, zend_free_op *should_free)
521 {
522 zval *ret = EX_VAR(var);
523
524 if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
525 *should_free = NULL;
526 ret = Z_INDIRECT_P(ret);
527 } else {
528 *should_free = ret;
529 }
530 return ret;
531 }
532
_get_zval_ptr_ptr(int op_type,znode_op node,const zend_execute_data * execute_data,zend_free_op * should_free,int type)533 static inline zval *_get_zval_ptr_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
534 {
535 if (op_type == IS_CV) {
536 *should_free = NULL;
537 return _get_zval_ptr_cv(execute_data, node.var, type);
538 } else /* if (op_type == IS_VAR) */ {
539 ZEND_ASSERT(op_type == IS_VAR);
540 return _get_zval_ptr_ptr_var(node.var, execute_data, should_free);
541 }
542 }
543
_get_obj_zval_ptr_unused(zend_execute_data * execute_data)544 static zend_always_inline zval *_get_obj_zval_ptr_unused(zend_execute_data *execute_data)
545 {
546 return &EX(This);
547 }
548
_get_obj_zval_ptr(int op_type,znode_op op,zend_execute_data * execute_data,zend_free_op * should_free,int type)549 static inline zval *_get_obj_zval_ptr(int op_type, znode_op op, zend_execute_data *execute_data, zend_free_op *should_free, int type)
550 {
551 if (op_type == IS_UNUSED) {
552 *should_free = NULL;
553 return &EX(This);
554 }
555 return get_zval_ptr(op_type, op, execute_data, should_free, type);
556 }
557
_get_obj_zval_ptr_undef(int op_type,znode_op op,zend_execute_data * execute_data,zend_free_op * should_free,int type)558 static inline zval *_get_obj_zval_ptr_undef(int op_type, znode_op op, zend_execute_data *execute_data, zend_free_op *should_free, int type)
559 {
560 if (op_type == IS_UNUSED) {
561 *should_free = NULL;
562 return &EX(This);
563 }
564 return get_zval_ptr_undef(op_type, op, execute_data, should_free, type);
565 }
566
_get_obj_zval_ptr_ptr(int op_type,znode_op node,zend_execute_data * execute_data,zend_free_op * should_free,int type)567 static inline zval *_get_obj_zval_ptr_ptr(int op_type, znode_op node, zend_execute_data *execute_data, zend_free_op *should_free, int type)
568 {
569 if (op_type == IS_UNUSED) {
570 *should_free = NULL;
571 return &EX(This);
572 }
573 return get_zval_ptr_ptr(op_type, node, execute_data, should_free, type);
574 }
575
zend_assign_to_variable_reference(zval * variable_ptr,zval * value_ptr)576 static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
577 {
578 zend_reference *ref;
579
580 if (EXPECTED(!Z_ISREF_P(value_ptr))) {
581 ZVAL_NEW_REF(value_ptr, value_ptr);
582 } else if (UNEXPECTED(variable_ptr == value_ptr)) {
583 return;
584 }
585
586 ref = Z_REF_P(value_ptr);
587 GC_REFCOUNT(ref)++;
588 if (Z_REFCOUNTED_P(variable_ptr)) {
589 zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
590
591 if (--GC_REFCOUNT(garbage) == 0) {
592 ZVAL_REF(variable_ptr, ref);
593 zval_dtor_func_for_ptr(garbage);
594 return;
595 } else {
596 GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
597 }
598 }
599 ZVAL_REF(variable_ptr, ref);
600 }
601
602 /* this should modify object only if it's empty */
make_real_object(zval * object)603 static inline int make_real_object(zval *object)
604 {
605 if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
606 if (UNEXPECTED(object == &EG(error_zval))) {
607 return 0;
608 } else if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
609 /* nothing to destroy */
610 } else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
611 zval_ptr_dtor_nogc(object);
612 } else {
613 return 0;
614 }
615 object_init(object);
616 zend_error(E_WARNING, "Creating default object from empty value");
617 }
618 return 1;
619 }
620
zend_verify_internal_arg_class_kind(const zend_internal_arg_info * cur_arg_info,char ** class_name,zend_class_entry ** pce)621 static char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce)
622 {
623 zend_string *key;
624 ALLOCA_FLAG(use_heap);
625
626 ZSTR_ALLOCA_INIT(key, cur_arg_info->class_name, strlen(cur_arg_info->class_name), use_heap);
627 *pce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
628 ZSTR_ALLOCA_FREE(key, use_heap);
629
630 *class_name = (*pce) ? ZSTR_VAL((*pce)->name) : (char*)cur_arg_info->class_name;
631 if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
632 return "implement interface ";
633 } else {
634 return "be an instance of ";
635 }
636 }
637
zend_verify_arg_class_kind(const zend_arg_info * cur_arg_info)638 static zend_always_inline zend_class_entry* zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info)
639 {
640 return zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
641 }
642
zend_verify_arg_error(const zend_function * zf,uint32_t arg_num,const char * need_msg,const char * need_kind,const char * given_msg,const char * given_kind,zval * arg)643 static ZEND_COLD void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
644 {
645 zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
646 const char *fname = ZSTR_VAL(zf->common.function_name);
647 const char *fsep;
648 const char *fclass;
649
650 if (zf->common.scope) {
651 fsep = "::";
652 fclass = ZSTR_VAL(zf->common.scope->name);
653 } else {
654 fsep = "";
655 fclass = "";
656 }
657
658 if (zf->common.type == ZEND_USER_FUNCTION) {
659 if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
660 zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d",
661 arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind,
662 ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno);
663 } else {
664 zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
665 }
666 } else {
667 zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
668 }
669 }
670
is_null_constant(zval * default_value)671 static int is_null_constant(zval *default_value)
672 {
673 if (Z_CONSTANT_P(default_value)) {
674 zval constant;
675
676 ZVAL_COPY_VALUE(&constant, default_value);
677 if (UNEXPECTED(zval_update_constant_ex(&constant, 0, NULL) != SUCCESS)) {
678 return 0;
679 }
680 if (Z_TYPE(constant) == IS_NULL) {
681 return 1;
682 }
683 zval_dtor(&constant);
684 }
685 return 0;
686 }
687
zend_verify_weak_scalar_type_hint(zend_uchar type_hint,zval * arg)688 static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg)
689 {
690 switch (type_hint) {
691 case _IS_BOOL: {
692 zend_bool dest;
693
694 if (!zend_parse_arg_bool_weak(arg, &dest)) {
695 return 0;
696 }
697 zval_ptr_dtor(arg);
698 ZVAL_BOOL(arg, dest);
699 return 1;
700 }
701 case IS_LONG: {
702 zend_long dest;
703
704 if (!zend_parse_arg_long_weak(arg, &dest)) {
705 return 0;
706 }
707 zval_ptr_dtor(arg);
708 ZVAL_LONG(arg, dest);
709 return 1;
710 }
711 case IS_DOUBLE: {
712 double dest;
713
714 if (!zend_parse_arg_double_weak(arg, &dest)) {
715 return 0;
716 }
717 zval_ptr_dtor(arg);
718 ZVAL_DOUBLE(arg, dest);
719 return 1;
720 }
721 case IS_STRING: {
722 zend_string *dest;
723
724 /* on success "arg" is converted to IS_STRING */
725 if (!zend_parse_arg_str_weak(arg, &dest)) {
726 return 0;
727 }
728 return 1;
729 }
730 default:
731 return 0;
732 }
733 }
734
zend_verify_scalar_type_hint(zend_uchar type_hint,zval * arg,zend_bool strict)735 static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, zend_bool strict)
736 {
737 if (UNEXPECTED(strict)) {
738 /* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
739 if (type_hint != IS_DOUBLE || Z_TYPE_P(arg) != IS_LONG) {
740 return 0;
741 }
742 } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
743 /* NULL may be accepted only by nullable hints (this is already checked) */
744 return 0;
745 }
746 return zend_verify_weak_scalar_type_hint(type_hint, arg);
747 }
748
zend_verify_internal_arg_type(zend_function * zf,uint32_t arg_num,zval * arg)749 static int zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg)
750 {
751 zend_internal_arg_info *cur_arg_info;
752 char *need_msg, *class_name;
753 zend_class_entry *ce;
754
755 if (EXPECTED(arg_num <= zf->internal_function.num_args)) {
756 cur_arg_info = &zf->internal_function.arg_info[arg_num-1];
757 } else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) {
758 cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args];
759 } else {
760 return 1;
761 }
762
763 if (cur_arg_info->type_hint) {
764 ZVAL_DEREF(arg);
765 if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
766 if (cur_arg_info->class_name) {
767 need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
768 if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
769 zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
770 return 0;
771 }
772 }
773 } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
774 if (cur_arg_info->class_name) {
775 need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
776 zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
777 return 0;
778 } else if (cur_arg_info->type_hint == IS_CALLABLE) {
779 if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
780 zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
781 return 0;
782 }
783 } else if (cur_arg_info->type_hint == _IS_BOOL &&
784 EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
785 /* pass */
786 } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
787 zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
788 return 0;
789 }
790 }
791 }
792 return 1;
793 }
794
zend_verify_arg_type(zend_function * zf,uint32_t arg_num,zval * arg,zval * default_value,void ** cache_slot)795 static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
796 {
797 zend_arg_info *cur_arg_info;
798 char *need_msg;
799 zend_class_entry *ce;
800
801 if (EXPECTED(arg_num <= zf->common.num_args)) {
802 cur_arg_info = &zf->common.arg_info[arg_num-1];
803 } else if (UNEXPECTED(zf->common.fn_flags & ZEND_ACC_VARIADIC)) {
804 cur_arg_info = &zf->common.arg_info[zf->common.num_args];
805 } else {
806 return 1;
807 }
808
809 if (cur_arg_info->type_hint) {
810 ZVAL_DEREF(arg);
811 if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
812 if (cur_arg_info->class_name) {
813 if (EXPECTED(*cache_slot)) {
814 ce = (zend_class_entry*)*cache_slot;
815 } else {
816 ce = zend_verify_arg_class_kind(cur_arg_info);
817 if (UNEXPECTED(!ce)) {
818 zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
819 return 0;
820 }
821 *cache_slot = (void*)ce;
822 }
823 if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(arg), ce))) {
824 need_msg =
825 (ce->ce_flags & ZEND_ACC_INTERFACE) ?
826 "implement interface " : "be an instance of ";
827 zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
828 return 0;
829 }
830 }
831 } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
832 if (cur_arg_info->class_name) {
833 if (EXPECTED(*cache_slot)) {
834 ce = (zend_class_entry*)*cache_slot;
835 } else {
836 ce = zend_verify_arg_class_kind(cur_arg_info);
837 if (UNEXPECTED(!ce)) {
838 ZEND_ASSERT(Z_TYPE_P(arg) != IS_OBJECT);
839 zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "", zend_zval_type_name(arg), arg);
840 return 0;
841 }
842 *cache_slot = (void*)ce;
843 }
844 need_msg =
845 (ce->ce_flags & ZEND_ACC_INTERFACE) ?
846 "implement interface " : "be an instance of ";
847 zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), zend_zval_type_name(arg), "", arg);
848 return 0;
849 } else if (cur_arg_info->type_hint == IS_CALLABLE) {
850 if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
851 zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
852 return 0;
853 }
854 } else if (cur_arg_info->type_hint == _IS_BOOL &&
855 EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
856 /* pass */
857 } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_ARG_USES_STRICT_TYPES()))) {
858 zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
859 return 0;
860 }
861 }
862 }
863 return 1;
864 }
865
zend_verify_missing_arg_type(zend_function * zf,uint32_t arg_num,void ** cache_slot)866 static zend_always_inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num, void **cache_slot)
867 {
868 zend_arg_info *cur_arg_info;
869 char *need_msg;
870 zend_class_entry *ce;
871
872 if (EXPECTED(arg_num <= zf->common.num_args)) {
873 cur_arg_info = &zf->common.arg_info[arg_num-1];
874 } else if (UNEXPECTED(zf->common.fn_flags & ZEND_ACC_VARIADIC)) {
875 cur_arg_info = &zf->common.arg_info[zf->common.num_args];
876 } else {
877 return 1;
878 }
879
880 if (cur_arg_info->type_hint) {
881 if (cur_arg_info->class_name) {
882 if (EXPECTED(*cache_slot)) {
883 ce = (zend_class_entry*)*cache_slot;
884 } else {
885 ce = zend_verify_arg_class_kind(cur_arg_info);
886 if (UNEXPECTED(!ce)) {
887 zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "none", "", NULL);
888 return 0;
889 }
890 *cache_slot = (void*)ce;
891 }
892 need_msg =
893 (ce->ce_flags & ZEND_ACC_INTERFACE) ?
894 "implement interface " : "be an instance of ";
895 zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), "none", "", NULL);
896 } else if (cur_arg_info->type_hint == IS_CALLABLE) {
897 zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
898 } else {
899 zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL);
900 }
901 return 0;
902 }
903 return 1;
904 }
905
zend_verify_missing_arg(zend_execute_data * execute_data,uint32_t arg_num,void ** cache_slot)906 static ZEND_COLD void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num, void **cache_slot)
907 {
908 if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
909 UNEXPECTED(zend_verify_missing_arg_type(EX(func), arg_num, cache_slot))) {
910 const char *class_name = EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "";
911 const char *space = EX(func)->common.scope ? "::" : "";
912 const char *func_name = EX(func)->common.function_name ? ZSTR_VAL(EX(func)->common.function_name) : "main";
913 zend_execute_data *ptr = EX(prev_execute_data);
914
915 if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
916 zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno);
917 } else {
918 zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name);
919 }
920 }
921 }
922
zend_verify_return_error(const zend_function * zf,const char * need_msg,const char * need_kind,const char * returned_msg,const char * returned_kind)923 static ZEND_COLD void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
924 {
925 const char *fname = ZSTR_VAL(zf->common.function_name);
926 const char *fsep;
927 const char *fclass;
928
929 if (zf->common.scope) {
930 fsep = "::";
931 fclass = ZSTR_VAL(zf->common.scope->name);
932 } else {
933 fsep = "";
934 fclass = "";
935 }
936
937 zend_type_error("Return value of %s%s%s() must %s%s, %s%s returned",
938 fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
939 }
940
zend_verify_internal_return_error(const zend_function * zf,const char * need_msg,const char * need_kind,const char * returned_msg,const char * returned_kind)941 static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
942 {
943 const char *fname = ZSTR_VAL(zf->common.function_name);
944 const char *fsep;
945 const char *fclass;
946
947 if (zf->common.scope) {
948 fsep = "::";
949 fclass = ZSTR_VAL(zf->common.scope->name);
950 } else {
951 fsep = "";
952 fclass = "";
953 }
954
955 zend_error_noreturn(E_CORE_ERROR, "Return value of %s%s%s() must %s%s, %s%s returned",
956 fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
957 }
958
959 #if ZEND_DEBUG
zend_verify_internal_return_type(zend_function * zf,zval * ret)960 static int zend_verify_internal_return_type(zend_function *zf, zval *ret)
961 {
962 zend_arg_info *ret_info = zf->common.arg_info - 1;
963 char *need_msg, *class_name;
964 zend_class_entry *ce;
965
966
967 if (ret_info->type_hint) {
968 if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
969 if (ret_info->class_name) {
970 need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
971 if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
972 zend_verify_internal_return_error(zf, need_msg, class_name, "instance of ", ZSTR_VAL(Z_OBJCE_P(ret)->name));
973 return 0;
974 }
975 }
976 } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
977 if (ret_info->class_name) {
978 need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
979 zend_verify_internal_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
980 } else if (ret_info->type_hint == IS_CALLABLE) {
981 if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
982 zend_verify_internal_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
983 return 0;
984 }
985 } else if (ret_info->type_hint == _IS_BOOL &&
986 EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
987 /* pass */
988 } else {
989 /* Use strict check to verify return value of internal function */
990 zend_verify_internal_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
991 return 0;
992 }
993 }
994 }
995 return 1;
996 }
997 #endif
998
zend_verify_return_type(zend_function * zf,zval * ret,void ** cache_slot)999 static zend_always_inline void zend_verify_return_type(zend_function *zf, zval *ret, void **cache_slot)
1000 {
1001 zend_arg_info *ret_info = zf->common.arg_info - 1;
1002 char *need_msg;
1003 zend_class_entry *ce;
1004
1005 if (ret_info->type_hint) {
1006 if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
1007 if (ret_info->class_name) {
1008 if (EXPECTED(*cache_slot)) {
1009 ce = (zend_class_entry*)*cache_slot;
1010 } else {
1011 ce = zend_verify_arg_class_kind(ret_info);
1012 if (UNEXPECTED(!ce)) {
1013 zend_verify_return_error(zf, "be an instance of ", ZSTR_VAL(ret_info->class_name), "instance of ", ZSTR_VAL(Z_OBJCE_P(ret)->name));
1014 return;
1015 }
1016 *cache_slot = (void*)ce;
1017 }
1018 if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(ret), ce))) {
1019 need_msg =
1020 (ce->ce_flags & ZEND_ACC_INTERFACE) ?
1021 "implement interface " : "be an instance of ";
1022 zend_verify_return_error(zf, need_msg, ZSTR_VAL(ce->name), "instance of ", ZSTR_VAL(Z_OBJCE_P(ret)->name));
1023 }
1024 }
1025 } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
1026 if (ret_info->class_name) {
1027 if (EXPECTED(*cache_slot)) {
1028 ce = (zend_class_entry*)*cache_slot;
1029 } else {
1030 ce = zend_verify_arg_class_kind(ret_info);
1031 if (UNEXPECTED(!ce)) {
1032 zend_verify_return_error(zf, "be an instance of ", ZSTR_VAL(ret_info->class_name), zend_zval_type_name(ret), "");
1033 return;
1034 }
1035 *cache_slot = (void*)ce;
1036 }
1037 need_msg =
1038 (ce->ce_flags & ZEND_ACC_INTERFACE) ?
1039 "implement interface " : "be an instance of ";
1040 zend_verify_return_error(zf, need_msg, ZSTR_VAL(ce->name), zend_zval_type_name(ret), "");
1041 } else if (ret_info->type_hint == IS_CALLABLE) {
1042 if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL)) {
1043 zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
1044 }
1045 } else if (ret_info->type_hint == _IS_BOOL &&
1046 EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
1047 /* pass */
1048 } else if (UNEXPECTED(!zend_verify_scalar_type_hint(ret_info->type_hint, ret, ZEND_RET_USES_STRICT_TYPES()))) {
1049 zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
1050 }
1051 }
1052 }
1053 }
1054
zend_verify_missing_return_type(zend_function * zf,void ** cache_slot)1055 static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **cache_slot)
1056 {
1057 zend_arg_info *ret_info = zf->common.arg_info - 1;
1058 char *need_msg;
1059 zend_class_entry *ce;
1060
1061 if (ret_info->type_hint) {
1062 if (ret_info->class_name) {
1063 if (EXPECTED(*cache_slot)) {
1064 ce = (zend_class_entry*)*cache_slot;
1065 } else {
1066 ce = zend_verify_arg_class_kind(ret_info);
1067 if (UNEXPECTED(!ce)) {
1068 zend_verify_return_error(zf, "be an instance of ", ZSTR_VAL(ret_info->class_name), "none", "");
1069 return 0;
1070 }
1071 *cache_slot = (void*)ce;
1072 }
1073 need_msg =
1074 (ce->ce_flags & ZEND_ACC_INTERFACE) ?
1075 "implement interface " : "be an instance of ";
1076 zend_verify_return_error(zf, need_msg, ZSTR_VAL(ce->name), "none", "");
1077 return 0;
1078 } else if (ret_info->type_hint == IS_CALLABLE) {
1079 zend_verify_return_error(zf, "be callable", "", "none", "");
1080 } else {
1081 zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), "none", "");
1082 }
1083 return 0;
1084 }
1085 return 1;
1086 }
1087
zend_assign_to_object(zval * retval,zval * object,uint32_t object_op_type,zval * property_name,uint32_t property_op_type,int value_type,znode_op value_op,const zend_execute_data * execute_data,void ** cache_slot)1088 static zend_always_inline void zend_assign_to_object(zval *retval, zval *object, uint32_t object_op_type, zval *property_name, uint32_t property_op_type, int value_type, znode_op value_op, const zend_execute_data *execute_data, void **cache_slot)
1089 {
1090 zend_free_op free_value;
1091 zval *value = get_zval_ptr_r(value_type, value_op, execute_data, &free_value);
1092 zval tmp;
1093
1094 if (object_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
1095 do {
1096 if (object_op_type == IS_VAR && UNEXPECTED(object == &EG(error_zval))) {
1097 if (retval) {
1098 ZVAL_NULL(retval);
1099 }
1100 FREE_OP(free_value);
1101 return;
1102 }
1103 if (Z_ISREF_P(object)) {
1104 object = Z_REFVAL_P(object);
1105 if (EXPECTED(Z_TYPE_P(object) == IS_OBJECT)) {
1106 break;
1107 }
1108 }
1109 if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE ||
1110 (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
1111 zend_object *obj;
1112
1113 zval_ptr_dtor(object);
1114 object_init(object);
1115 Z_ADDREF_P(object);
1116 obj = Z_OBJ_P(object);
1117 zend_error(E_WARNING, "Creating default object from empty value");
1118 if (GC_REFCOUNT(obj) == 1) {
1119 /* the enclosing container was deleted, obj is unreferenced */
1120 if (retval) {
1121 ZVAL_NULL(retval);
1122 }
1123 FREE_OP(free_value);
1124 OBJ_RELEASE(obj);
1125 return;
1126 }
1127 Z_DELREF_P(object);
1128 } else {
1129 zend_error(E_WARNING, "Attempt to assign property of non-object");
1130 if (retval) {
1131 ZVAL_NULL(retval);
1132 }
1133 FREE_OP(free_value);
1134 return;
1135 }
1136 } while (0);
1137 }
1138
1139 if (property_op_type == IS_CONST &&
1140 EXPECTED(Z_OBJCE_P(object) == CACHED_PTR_EX(cache_slot))) {
1141 uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
1142 zend_object *zobj = Z_OBJ_P(object);
1143 zval *property;
1144
1145 if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
1146 property = OBJ_PROP(zobj, prop_offset);
1147 if (Z_TYPE_P(property) != IS_UNDEF) {
1148 fast_assign:
1149 value = zend_assign_to_variable(property, value, value_type);
1150 if (retval && EXPECTED(!EG(exception))) {
1151 ZVAL_COPY(retval, value);
1152 }
1153 return;
1154 }
1155 } else {
1156 if (EXPECTED(zobj->properties != NULL)) {
1157 if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
1158 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
1159 GC_REFCOUNT(zobj->properties)--;
1160 }
1161 zobj->properties = zend_array_dup(zobj->properties);
1162 }
1163 property = zend_hash_find(zobj->properties, Z_STR_P(property_name));
1164 if (property) {
1165 goto fast_assign;
1166 }
1167 }
1168
1169 if (!zobj->ce->__set) {
1170
1171 if (EXPECTED(zobj->properties == NULL)) {
1172 rebuild_object_properties(zobj);
1173 }
1174 /* separate our value if necessary */
1175 if (value_type == IS_CONST) {
1176 if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
1177 ZVAL_COPY_VALUE(&tmp, value);
1178 zval_copy_ctor_func(&tmp);
1179 value = &tmp;
1180 }
1181 } else if (value_type != IS_TMP_VAR) {
1182 if (Z_ISREF_P(value)) {
1183 if (value_type == IS_VAR) {
1184 zend_reference *ref = Z_REF_P(value);
1185 if (--(GC_REFCOUNT(ref)) == 0) {
1186 ZVAL_COPY_VALUE(&tmp, Z_REFVAL_P(value));
1187 efree_size(ref, sizeof(zend_reference));
1188 value = &tmp;
1189 } else {
1190 value = Z_REFVAL_P(value);
1191 if (Z_REFCOUNTED_P(value)) {
1192 Z_ADDREF_P(value);
1193 }
1194 }
1195 } else {
1196 value = Z_REFVAL_P(value);
1197 if (Z_REFCOUNTED_P(value)) {
1198 Z_ADDREF_P(value);
1199 }
1200 }
1201 } else if (value_type == IS_CV && Z_REFCOUNTED_P(value)) {
1202 Z_ADDREF_P(value);
1203 }
1204 }
1205 zend_hash_add_new(zobj->properties, Z_STR_P(property_name), value);
1206 if (retval) {
1207 ZVAL_COPY(retval, value);
1208 }
1209 return;
1210 }
1211 }
1212 }
1213
1214 if (!Z_OBJ_HT_P(object)->write_property) {
1215 zend_error(E_WARNING, "Attempt to assign property of non-object");
1216 if (retval) {
1217 ZVAL_NULL(retval);
1218 }
1219 FREE_OP(free_value);
1220 return;
1221 }
1222
1223 /* separate our value if necessary */
1224 if (value_type == IS_CONST) {
1225 if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
1226 ZVAL_COPY_VALUE(&tmp, value);
1227 zval_copy_ctor_func(&tmp);
1228 value = &tmp;
1229 }
1230 } else if (value_type != IS_TMP_VAR) {
1231 ZVAL_DEREF(value);
1232 }
1233
1234 Z_OBJ_HT_P(object)->write_property(object, property_name, value, cache_slot);
1235
1236 if (retval && EXPECTED(!EG(exception))) {
1237 ZVAL_COPY(retval, value);
1238 }
1239 if (value_type == IS_CONST) {
1240 zval_ptr_dtor_nogc(value);
1241 } else {
1242 FREE_OP(free_value);
1243 }
1244 }
1245
zend_assign_to_object_dim(zval * retval,zval * object,zval * property_name,int value_type,znode_op value_op,const zend_execute_data * execute_data)1246 static zend_never_inline void zend_assign_to_object_dim(zval *retval, zval *object, zval *property_name, int value_type, znode_op value_op, const zend_execute_data *execute_data)
1247 {
1248 zend_free_op free_value;
1249 zval *value = get_zval_ptr_deref(value_type, value_op, execute_data, &free_value, BP_VAR_R);
1250 zval tmp;
1251
1252 /* Note: property_name in this case is really the array index! */
1253 if (!Z_OBJ_HT_P(object)->write_dimension) {
1254 zend_throw_error(NULL, "Cannot use object as array");
1255 FREE_OP(free_value);
1256 return;
1257 }
1258
1259 /* separate our value if necessary */
1260 if (value_type == IS_CONST) {
1261 if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
1262 ZVAL_COPY_VALUE(&tmp, value);
1263 zval_copy_ctor_func(&tmp);
1264 value = &tmp;
1265 }
1266 }
1267
1268 Z_OBJ_HT_P(object)->write_dimension(object, property_name, value);
1269
1270 if (retval && EXPECTED(!EG(exception))) {
1271 ZVAL_COPY(retval, value);
1272 }
1273 if (value_type == IS_CONST) {
1274 zval_ptr_dtor_nogc(value);
1275 } else {
1276 FREE_OP(free_value);
1277 }
1278 }
1279
zend_binary_assign_op_obj_dim(zval * object,zval * property,zval * value,zval * retval,binary_op_type binary_op)1280 static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, binary_op_type binary_op)
1281 {
1282 zval *z;
1283 zval rv, res;
1284
1285 if (Z_OBJ_HT_P(object)->read_dimension &&
1286 (z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv)) != NULL) {
1287
1288 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
1289 zval rv2;
1290 zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
1291
1292 if (z == &rv) {
1293 zval_ptr_dtor(&rv);
1294 }
1295 ZVAL_COPY_VALUE(z, value);
1296 }
1297 binary_op(&res, Z_ISREF_P(z) ? Z_REFVAL_P(z) : z, value);
1298 Z_OBJ_HT_P(object)->write_dimension(object, property, &res);
1299 if (z == &rv) {
1300 zval_ptr_dtor(&rv);
1301 }
1302 if (retval) {
1303 ZVAL_COPY(retval, &res);
1304 }
1305 zval_ptr_dtor(&res);
1306 } else {
1307 zend_error(E_WARNING, "Attempt to assign property of non-object");
1308 if (retval) {
1309 ZVAL_NULL(retval);
1310 }
1311 }
1312 }
1313
zend_assign_to_string_offset(zval * str,zend_long offset,zval * value,zval * result)1314 static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, zval *result)
1315 {
1316 zend_string *old_str;
1317
1318 if (offset < 0) {
1319 zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset);
1320 zend_string_release(Z_STR_P(str));
1321 if (result) {
1322 ZVAL_NULL(result);
1323 }
1324 return;
1325 }
1326
1327 old_str = Z_STR_P(str);
1328 if ((size_t)offset >= Z_STRLEN_P(str)) {
1329 zend_long old_len = Z_STRLEN_P(str);
1330 Z_STR_P(str) = zend_string_extend(Z_STR_P(str), offset + 1, 0);
1331 Z_TYPE_INFO_P(str) = IS_STRING_EX;
1332 memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
1333 Z_STRVAL_P(str)[offset+1] = 0;
1334 } else if (!Z_REFCOUNTED_P(str)) {
1335 Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
1336 Z_TYPE_INFO_P(str) = IS_STRING_EX;
1337 }
1338
1339 if (Z_TYPE_P(value) != IS_STRING) {
1340 zend_string *tmp = zval_get_string(value);
1341
1342 Z_STRVAL_P(str)[offset] = ZSTR_VAL(tmp)[0];
1343 zend_string_release(tmp);
1344 } else {
1345 Z_STRVAL_P(str)[offset] = Z_STRVAL_P(value)[0];
1346 zend_string_forget_hash_val(Z_STR_P(str));
1347 }
1348 /*
1349 * the value of an assignment to a string offset is undefined
1350 T(result->u.var).var = &T->str_offset.str;
1351 */
1352
1353 zend_string_release(old_str);
1354 if (result) {
1355 zend_uchar c = (zend_uchar)Z_STRVAL_P(str)[offset];
1356
1357 if (CG(one_char_string)[c]) {
1358 ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
1359 } else {
1360 ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(str) + offset, 1, 0));
1361 }
1362 }
1363 }
1364
zend_post_incdec_overloaded_property(zval * object,zval * property,void ** cache_slot,int inc,zval * result)1365 static zend_never_inline void zend_post_incdec_overloaded_property(zval *object, zval *property, void **cache_slot, int inc, zval *result)
1366 {
1367 if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) {
1368 zval rv, obj;
1369 zval *z;
1370 zval z_copy;
1371
1372 ZVAL_OBJ(&obj, Z_OBJ_P(object));
1373 Z_ADDREF(obj);
1374 z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
1375 if (UNEXPECTED(EG(exception))) {
1376 OBJ_RELEASE(Z_OBJ(obj));
1377 return;
1378 }
1379
1380 if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) {
1381 zval rv2;
1382 zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
1383 if (z == &rv) {
1384 zval_ptr_dtor(&rv);
1385 }
1386 ZVAL_COPY_VALUE(z, value);
1387 }
1388
1389 if (UNEXPECTED(Z_TYPE_P(z) == IS_REFERENCE)) {
1390 ZVAL_COPY(result, Z_REFVAL_P(z));
1391 } else {
1392 ZVAL_COPY(result, z);
1393 }
1394 ZVAL_DUP(&z_copy, result);
1395 if (inc) {
1396 increment_function(&z_copy);
1397 } else {
1398 decrement_function(&z_copy);
1399 }
1400 Z_OBJ_HT(obj)->write_property(&obj, property, &z_copy, cache_slot);
1401 OBJ_RELEASE(Z_OBJ(obj));
1402 zval_ptr_dtor(&z_copy);
1403 zval_ptr_dtor(z);
1404 } else {
1405 zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
1406 ZVAL_NULL(result);
1407 }
1408 }
1409
zend_pre_incdec_overloaded_property(zval * object,zval * property,void ** cache_slot,int inc,zval * result)1410 static zend_never_inline void zend_pre_incdec_overloaded_property(zval *object, zval *property, void **cache_slot, int inc, zval *result)
1411 {
1412 zval rv;
1413
1414 if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) {
1415 zval *z, *zptr, obj;
1416
1417 ZVAL_OBJ(&obj, Z_OBJ_P(object));
1418 Z_ADDREF(obj);
1419 zptr = z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
1420 if (UNEXPECTED(EG(exception))) {
1421 OBJ_RELEASE(Z_OBJ(obj));
1422 return;
1423 }
1424
1425 if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) {
1426 zval rv2;
1427 zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
1428
1429 if (z == &rv) {
1430 zval_ptr_dtor(&rv);
1431 }
1432 ZVAL_COPY_VALUE(z, value);
1433 }
1434 ZVAL_DEREF(z);
1435 SEPARATE_ZVAL_NOREF(z);
1436 if (inc) {
1437 increment_function(z);
1438 } else {
1439 decrement_function(z);
1440 }
1441 if (UNEXPECTED(result)) {
1442 ZVAL_COPY(result, z);
1443 }
1444 Z_OBJ_HT(obj)->write_property(&obj, property, z, cache_slot);
1445 OBJ_RELEASE(Z_OBJ(obj));
1446 zval_ptr_dtor(zptr);
1447 } else {
1448 zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
1449 if (UNEXPECTED(result)) {
1450 ZVAL_NULL(result);
1451 }
1452 }
1453 }
1454
zend_assign_op_overloaded_property(zval * object,zval * property,void ** cache_slot,zval * value,binary_op_type binary_op,zval * result)1455 static zend_never_inline void zend_assign_op_overloaded_property(zval *object, zval *property, void **cache_slot, zval *value, binary_op_type binary_op, zval *result)
1456 {
1457 zval *z;
1458 zval rv, obj;
1459 zval *zptr;
1460
1461 ZVAL_OBJ(&obj, Z_OBJ_P(object));
1462 Z_ADDREF(obj);
1463 if (EXPECTED(Z_OBJ_HT(obj)->read_property)) {
1464 z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv);
1465 if (UNEXPECTED(EG(exception))) {
1466 OBJ_RELEASE(Z_OBJ(obj));
1467 return;
1468 }
1469 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
1470 zval rv2;
1471 zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
1472
1473 if (z == &rv) {
1474 zval_ptr_dtor(&rv);
1475 }
1476 ZVAL_COPY_VALUE(z, value);
1477 }
1478 zptr = z;
1479 ZVAL_DEREF(z);
1480 SEPARATE_ZVAL_NOREF(z);
1481 binary_op(z, z, value);
1482 Z_OBJ_HT(obj)->write_property(&obj, property, z, cache_slot);
1483 if (UNEXPECTED(result)) {
1484 ZVAL_COPY(result, z);
1485 }
1486 zval_ptr_dtor(zptr);
1487 } else {
1488 zend_error(E_WARNING, "Attempt to assign property of non-object");
1489 if (UNEXPECTED(result)) {
1490 ZVAL_NULL(result);
1491 }
1492 }
1493 OBJ_RELEASE(Z_OBJ(obj));
1494 }
1495
1496 /* Utility Functions for Extensions */
zend_extension_statement_handler(const zend_extension * extension,zend_op_array * op_array)1497 static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array)
1498 {
1499 if (extension->statement_handler) {
1500 extension->statement_handler(op_array);
1501 }
1502 }
1503
1504
zend_extension_fcall_begin_handler(const zend_extension * extension,zend_op_array * op_array)1505 static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array)
1506 {
1507 if (extension->fcall_begin_handler) {
1508 extension->fcall_begin_handler(op_array);
1509 }
1510 }
1511
1512
zend_extension_fcall_end_handler(const zend_extension * extension,zend_op_array * op_array)1513 static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array)
1514 {
1515 if (extension->fcall_end_handler) {
1516 extension->fcall_end_handler(op_array);
1517 }
1518 }
1519
1520
zend_get_target_symbol_table(zend_execute_data * execute_data,int fetch_type)1521 static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_data *execute_data, int fetch_type)
1522 {
1523 HashTable *ht;
1524
1525 if (EXPECTED(fetch_type == ZEND_FETCH_GLOBAL_LOCK) ||
1526 EXPECTED(fetch_type == ZEND_FETCH_GLOBAL)) {
1527 ht = &EG(symbol_table);
1528 } else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
1529 ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
1530 ht = EX(func)->op_array.static_variables;
1531 if (GC_REFCOUNT(ht) > 1) {
1532 if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
1533 GC_REFCOUNT(ht)--;
1534 }
1535 EX(func)->op_array.static_variables = ht = zend_array_dup(ht);
1536 }
1537 } else {
1538 ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
1539 if (!EX(symbol_table)) {
1540 zend_rebuild_symbol_table();
1541 }
1542 ht = EX(symbol_table);
1543 }
1544 return ht;
1545 }
1546
zend_fetch_dimension_address_inner(HashTable * ht,const zval * dim,int dim_type,int type)1547 static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type)
1548 {
1549 zval *retval;
1550 zend_string *offset_key;
1551 zend_ulong hval;
1552
1553 try_again:
1554 if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
1555 hval = Z_LVAL_P(dim);
1556 num_index:
1557 retval = zend_hash_index_find(ht, hval);
1558 if (retval == NULL) {
1559 switch (type) {
1560 case BP_VAR_R:
1561 zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
1562 /* break missing intentionally */
1563 case BP_VAR_UNSET:
1564 case BP_VAR_IS:
1565 retval = &EG(uninitialized_zval);
1566 break;
1567 case BP_VAR_RW:
1568 zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
1569 retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
1570 break;
1571 case BP_VAR_W:
1572 retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
1573 break;
1574 }
1575 }
1576 } else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
1577 offset_key = Z_STR_P(dim);
1578 if (dim_type != IS_CONST) {
1579 if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
1580 goto num_index;
1581 }
1582 }
1583 str_index:
1584 retval = zend_hash_find(ht, offset_key);
1585 if (retval) {
1586 /* support for $GLOBALS[...] */
1587 if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
1588 retval = Z_INDIRECT_P(retval);
1589 if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
1590 switch (type) {
1591 case BP_VAR_R:
1592 zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
1593 /* break missing intentionally */
1594 case BP_VAR_UNSET:
1595 case BP_VAR_IS:
1596 retval = &EG(uninitialized_zval);
1597 break;
1598 case BP_VAR_RW:
1599 zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
1600 /* break missing intentionally */
1601 case BP_VAR_W:
1602 ZVAL_NULL(retval);
1603 break;
1604 }
1605 }
1606 }
1607 } else {
1608 switch (type) {
1609 case BP_VAR_R:
1610 zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
1611 /* break missing intentionally */
1612 case BP_VAR_UNSET:
1613 case BP_VAR_IS:
1614 retval = &EG(uninitialized_zval);
1615 break;
1616 case BP_VAR_RW:
1617 zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
1618 retval = zend_hash_update(ht, offset_key, &EG(uninitialized_zval));
1619 break;
1620 case BP_VAR_W:
1621 retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
1622 break;
1623 }
1624 }
1625 } else {
1626 switch (Z_TYPE_P(dim)) {
1627 case IS_NULL:
1628 offset_key = ZSTR_EMPTY_ALLOC();
1629 goto str_index;
1630 case IS_DOUBLE:
1631 hval = zend_dval_to_lval(Z_DVAL_P(dim));
1632 goto num_index;
1633 case IS_RESOURCE:
1634 zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
1635 hval = Z_RES_HANDLE_P(dim);
1636 goto num_index;
1637 case IS_FALSE:
1638 hval = 0;
1639 goto num_index;
1640 case IS_TRUE:
1641 hval = 1;
1642 goto num_index;
1643 case IS_REFERENCE:
1644 dim = Z_REFVAL_P(dim);
1645 goto try_again;
1646 default:
1647 zend_error(E_WARNING, "Illegal offset type");
1648 retval = (type == BP_VAR_W || type == BP_VAR_RW) ?
1649 &EG(error_zval) : &EG(uninitialized_zval);
1650 }
1651 }
1652 return retval;
1653 }
1654
zend_check_string_offset(zval * dim,int type)1655 static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type)
1656 {
1657 zend_long offset;
1658
1659 try_again:
1660 if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1661 switch(Z_TYPE_P(dim)) {
1662 case IS_STRING:
1663 if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1664 break;
1665 }
1666 if (type != BP_VAR_UNSET) {
1667 zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1668 }
1669 break;
1670 case IS_DOUBLE:
1671 case IS_NULL:
1672 case IS_FALSE:
1673 case IS_TRUE:
1674 zend_error(E_NOTICE, "String offset cast occurred");
1675 break;
1676 case IS_REFERENCE:
1677 dim = Z_REFVAL_P(dim);
1678 goto try_again;
1679 default:
1680 zend_error(E_WARNING, "Illegal offset type");
1681 break;
1682 }
1683
1684 offset = zval_get_long(dim);
1685 } else {
1686 offset = Z_LVAL_P(dim);
1687 }
1688
1689 return offset;
1690 }
1691
zend_fetch_string_offset(zval * container,zval * dim,int type)1692 static zend_always_inline zend_long zend_fetch_string_offset(zval *container, zval *dim, int type)
1693 {
1694 zend_long offset = zend_check_string_offset(dim, type);
1695
1696 if (Z_REFCOUNTED_P(container)) {
1697 if (Z_REFCOUNT_P(container) > 1) {
1698 Z_DELREF_P(container);
1699 zval_copy_ctor_func(container);
1700 }
1701 Z_ADDREF_P(container);
1702 }
1703 return offset;
1704 }
1705
zend_fetch_dimension_address(zval * result,zval * container,zval * dim,int dim_type,int type)1706 static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type)
1707 {
1708 zval *retval;
1709
1710 if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1711 try_array:
1712 SEPARATE_ARRAY(container);
1713 fetch_from_array:
1714 if (dim == NULL) {
1715 retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
1716 if (UNEXPECTED(retval == NULL)) {
1717 zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
1718 retval = &EG(error_zval);
1719 }
1720 } else {
1721 retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
1722 }
1723 ZVAL_INDIRECT(result, retval);
1724 return;
1725 } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
1726 container = Z_REFVAL_P(container);
1727 if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1728 goto try_array;
1729 }
1730 }
1731 if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1732 if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) {
1733 zval_ptr_dtor_nogc(container);
1734 convert_to_array:
1735 ZVAL_NEW_ARR(container);
1736 zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
1737 goto fetch_from_array;
1738 }
1739
1740 if (dim == NULL) {
1741 zend_throw_error(NULL, "[] operator not supported for strings");
1742 ZVAL_INDIRECT(result, &EG(error_zval));
1743 } else {
1744 zend_check_string_offset(dim, type);
1745 ZVAL_INDIRECT(result, NULL); /* wrong string offset */
1746 }
1747 } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1748 if (!Z_OBJ_HT_P(container)->read_dimension) {
1749 zend_throw_error(NULL, "Cannot use object as array");
1750 retval = &EG(error_zval);
1751 } else {
1752 retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
1753
1754 if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
1755 zend_class_entry *ce = Z_OBJCE_P(container);
1756
1757 ZVAL_NULL(result);
1758 zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
1759 } else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) {
1760 if (!Z_ISREF_P(retval)) {
1761 if (result != retval) {
1762 ZVAL_COPY(result, retval);
1763 retval = result;
1764 }
1765 if (Z_TYPE_P(retval) != IS_OBJECT) {
1766 zend_class_entry *ce = Z_OBJCE_P(container);
1767 zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
1768 }
1769 } else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) {
1770 ZVAL_UNREF(retval);
1771 }
1772 if (result != retval) {
1773 ZVAL_INDIRECT(result, retval);
1774 }
1775 } else {
1776 ZVAL_INDIRECT(result, &EG(error_zval));
1777 }
1778 }
1779 } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
1780 if (UNEXPECTED(container == &EG(error_zval))) {
1781 ZVAL_INDIRECT(result, &EG(error_zval));
1782 } else if (type != BP_VAR_UNSET) {
1783 goto convert_to_array;
1784 } else {
1785 /* for read-mode only */
1786 ZVAL_NULL(result);
1787 }
1788 } else {
1789 if (type == BP_VAR_UNSET) {
1790 zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1791 ZVAL_NULL(result);
1792 } else {
1793 zend_error(E_WARNING, "Cannot use a scalar value as an array");
1794 ZVAL_INDIRECT(result, &EG(error_zval));
1795 }
1796 }
1797 }
1798
zend_fetch_dimension_address_W(zval * result,zval * container_ptr,zval * dim,int dim_type)1799 static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type)
1800 {
1801 zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W);
1802 }
1803
zend_fetch_dimension_address_RW(zval * result,zval * container_ptr,zval * dim,int dim_type)1804 static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type)
1805 {
1806 zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW);
1807 }
1808
zend_fetch_dimension_address_UNSET(zval * result,zval * container_ptr,zval * dim,int dim_type)1809 static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type)
1810 {
1811 zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET);
1812 }
1813
zend_fetch_dimension_address_read(zval * result,zval * container,zval * dim,int dim_type,int type)1814 static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type)
1815 {
1816 zval *retval;
1817
1818 if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1819 try_array:
1820 retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
1821 ZVAL_COPY(result, retval);
1822 return;
1823 } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
1824 container = Z_REFVAL_P(container);
1825 if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
1826 goto try_array;
1827 }
1828 }
1829 if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1830 zend_long offset;
1831
1832 try_string_offset:
1833 if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1834 switch (Z_TYPE_P(dim)) {
1835 /* case IS_LONG: */
1836 case IS_STRING:
1837 if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1838 break;
1839 }
1840 if (type == BP_VAR_IS) {
1841 ZVAL_NULL(result);
1842 return;
1843 }
1844 zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1845 break;
1846 case IS_DOUBLE:
1847 case IS_NULL:
1848 case IS_FALSE:
1849 case IS_TRUE:
1850 if (type != BP_VAR_IS) {
1851 zend_error(E_NOTICE, "String offset cast occurred");
1852 }
1853 break;
1854 case IS_REFERENCE:
1855 dim = Z_REFVAL_P(dim);
1856 goto try_string_offset;
1857 default:
1858 zend_error(E_WARNING, "Illegal offset type");
1859 break;
1860 }
1861
1862 offset = zval_get_long(dim);
1863 } else {
1864 offset = Z_LVAL_P(dim);
1865 }
1866
1867 if (UNEXPECTED(offset < 0) || UNEXPECTED(Z_STRLEN_P(container) <= (size_t)offset)) {
1868 if (type != BP_VAR_IS) {
1869 zend_error(E_NOTICE, "Uninitialized string offset: %pd", offset);
1870 ZVAL_EMPTY_STRING(result);
1871 } else {
1872 ZVAL_NULL(result);
1873 }
1874 } else {
1875 zend_uchar c = (zend_uchar)Z_STRVAL_P(container)[offset];
1876
1877 if (CG(one_char_string)[c]) {
1878 ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
1879 } else {
1880 ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + offset, 1, 0));
1881 }
1882 }
1883 } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1884 if (!Z_OBJ_HT_P(container)->read_dimension) {
1885 zend_throw_error(NULL, "Cannot use object as array");
1886 ZVAL_NULL(result);
1887 } else {
1888 retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
1889
1890 ZEND_ASSERT(result != NULL);
1891 if (retval) {
1892 if (result != retval) {
1893 ZVAL_COPY(result, retval);
1894 }
1895 } else {
1896 ZVAL_NULL(result);
1897 }
1898 }
1899 } else {
1900 ZVAL_NULL(result);
1901 }
1902 }
1903
zend_fetch_dimension_address_read_R(zval * result,zval * container,zval * dim,int dim_type)1904 static zend_never_inline void zend_fetch_dimension_address_read_R(zval *result, zval *container, zval *dim, int dim_type)
1905 {
1906 zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R);
1907 }
1908
zend_fetch_dimension_address_read_IS(zval * result,zval * container,zval * dim,int dim_type)1909 static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zval *container, zval *dim, int dim_type)
1910 {
1911 zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS);
1912 }
1913
zend_fetch_dimension_by_zval(zval * result,zval * container,zval * dim)1914 ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim)
1915 {
1916 zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR);
1917 }
1918
zend_fetch_dimension_by_zval_is(zval * result,zval * container,zval * dim,int dim_type)1919 ZEND_API void zend_fetch_dimension_by_zval_is(zval *result, zval *container, zval *dim, int dim_type)
1920 {
1921 zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS);
1922 }
1923
1924
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)1925 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)
1926 {
1927 if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) {
1928 do {
1929 if (container_op_type == IS_VAR && UNEXPECTED(container == &EG(error_zval))) {
1930 ZVAL_INDIRECT(result, &EG(error_zval));
1931 return;
1932 }
1933
1934 if (Z_ISREF_P(container)) {
1935 container = Z_REFVAL_P(container);
1936 if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1937 break;
1938 }
1939 }
1940
1941 /* this should modify object only if it's empty */
1942 if (type != BP_VAR_UNSET &&
1943 EXPECTED(Z_TYPE_P(container) <= IS_FALSE ||
1944 (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0))) {
1945 zval_ptr_dtor_nogc(container);
1946 object_init(container);
1947 } else {
1948 zend_error(E_WARNING, "Attempt to modify property of non-object");
1949 ZVAL_INDIRECT(result, &EG(error_zval));
1950 return;
1951 }
1952 } while (0);
1953 }
1954 if (prop_op_type == IS_CONST &&
1955 EXPECTED(Z_OBJCE_P(container) == CACHED_PTR_EX(cache_slot))) {
1956 uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
1957 zend_object *zobj = Z_OBJ_P(container);
1958 zval *retval;
1959
1960 if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
1961 retval = OBJ_PROP(zobj, prop_offset);
1962 if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
1963 ZVAL_INDIRECT(result, retval);
1964 return;
1965 }
1966 } else if (EXPECTED(zobj->properties != NULL)) {
1967 if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
1968 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
1969 GC_REFCOUNT(zobj->properties)--;
1970 }
1971 zobj->properties = zend_array_dup(zobj->properties);
1972 }
1973 retval = zend_hash_find(zobj->properties, Z_STR_P(prop_ptr));
1974 if (EXPECTED(retval)) {
1975 ZVAL_INDIRECT(result, retval);
1976 return;
1977 }
1978 }
1979 }
1980 if (EXPECTED(Z_OBJ_HT_P(container)->get_property_ptr_ptr)) {
1981 zval *ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, type, cache_slot);
1982 if (NULL == ptr) {
1983 if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) {
1984 ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result);
1985 if (ptr != result) {
1986 ZVAL_INDIRECT(result, ptr);
1987 } else if (UNEXPECTED(Z_ISREF_P(ptr) && Z_REFCOUNT_P(ptr) == 1)) {
1988 ZVAL_UNREF(ptr);
1989 }
1990 } else {
1991 zend_throw_error(NULL, "Cannot access undefined property for object with overloaded property access");
1992 ZVAL_INDIRECT(result, &EG(error_zval));
1993 }
1994 } else {
1995 ZVAL_INDIRECT(result, ptr);
1996 }
1997 } else if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) {
1998 zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result);
1999 if (ptr != result) {
2000 ZVAL_INDIRECT(result, ptr);
2001 } else if (UNEXPECTED(Z_ISREF_P(ptr) && Z_REFCOUNT_P(ptr) == 1)) {
2002 ZVAL_UNREF(ptr);
2003 }
2004 } else {
2005 zend_error(E_WARNING, "This object doesn't support property references");
2006 ZVAL_INDIRECT(result, &EG(error_zval));
2007 }
2008 }
2009
2010 #if ZEND_INTENSIVE_DEBUGGING
2011
2012 #define CHECK_SYMBOL_TABLES() \
2013 zend_hash_apply(&EG(symbol_table), zend_check_symbol); \
2014 if (&EG(symbol_table)!=EX(symbol_table)) { \
2015 zend_hash_apply(EX(symbol_table), zend_check_symbol); \
2016 }
2017
zend_check_symbol(zval * pz)2018 static int zend_check_symbol(zval *pz)
2019 {
2020 if (Z_TYPE_P(pz) == IS_INDIRECT) {
2021 pz = Z_INDIRECT_P(pz);
2022 }
2023 if (Z_TYPE_P(pz) > 10) {
2024 fprintf(stderr, "Warning! %x has invalid type!\n", *pz);
2025 /* See http://support.microsoft.com/kb/190351 */
2026 #ifdef ZEND_WIN32
2027 fflush(stderr);
2028 #endif
2029 } else if (Z_TYPE_P(pz) == IS_ARRAY) {
2030 zend_hash_apply(Z_ARRVAL_P(pz), zend_check_symbol);
2031 } else if (Z_TYPE_P(pz) == IS_OBJECT) {
2032 /* OBJ-TBI - doesn't support new object model! */
2033 zend_hash_apply(Z_OBJPROP_P(pz), zend_check_symbol);
2034 }
2035
2036 return 0;
2037 }
2038
2039
2040 #else
2041 #define CHECK_SYMBOL_TABLES()
2042 #endif
2043
execute_internal(zend_execute_data * execute_data,zval * return_value)2044 ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value)
2045 {
2046 execute_data->func->internal_function.handler(execute_data, return_value);
2047 }
2048
zend_clean_and_cache_symbol_table(zend_array * symbol_table)2049 ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{ */
2050 {
2051 if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
2052 zend_array_destroy(symbol_table);
2053 } else {
2054 /* clean before putting into the cache, since clean
2055 could call dtors, which could use cached hash */
2056 zend_symtable_clean(symbol_table);
2057 *(++EG(symtable_cache_ptr)) = symbol_table;
2058 }
2059 }
2060 /* }}} */
2061
i_free_compiled_variables(zend_execute_data * execute_data)2062 static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
2063 {
2064 zval *cv = EX_VAR_NUM(0);
2065 zval *end = cv + EX(func)->op_array.last_var;
2066 while (EXPECTED(cv != end)) {
2067 if (Z_REFCOUNTED_P(cv)) {
2068 if (!Z_DELREF_P(cv)) {
2069 zend_refcounted *r = Z_COUNTED_P(cv);
2070 ZVAL_NULL(cv);
2071 zval_dtor_func_for_ptr(r);
2072 } else {
2073 GC_ZVAL_CHECK_POSSIBLE_ROOT(cv);
2074 }
2075 }
2076 cv++;
2077 }
2078 }
2079 /* }}} */
2080
zend_free_compiled_variables(zend_execute_data * execute_data)2081 void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
2082 {
2083 i_free_compiled_variables(execute_data);
2084 }
2085 /* }}} */
2086
2087 #ifdef ZEND_WIN32
2088 # define ZEND_VM_INTERRUPT_CHECK() do { \
2089 if (EG(timed_out)) { \
2090 zend_timeout(0); \
2091 } \
2092 } while (0)
2093 #else
2094 # define ZEND_VM_INTERRUPT_CHECK() do { \
2095 } while (0)
2096 #endif
2097
2098 /*
2099 * Stack Frame Layout (the whole stack frame is allocated at once)
2100 * ==================
2101 *
2102 * +========================================+
2103 * EG(current_execute_data) -> | zend_execute_data |
2104 * +----------------------------------------+
2105 * EX_CV_NUM(0) ---------> | VAR[0] = ARG[1] |
2106 * | ... |
2107 * | VAR[op_array->num_args-1] = ARG[N] |
2108 * | ... |
2109 * | VAR[op_array->last_var-1] |
2110 * | VAR[op_array->last_var] = TMP[0] |
2111 * | ... |
2112 * | VAR[op_array->last_var+op_array->T-1] |
2113 * | ARG[N+1] (extra_args) |
2114 * | ... |
2115 * +----------------------------------------+
2116 */
2117
i_init_func_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value,int check_this)2118 static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */
2119 {
2120 uint32_t first_extra_arg, num_args;
2121 ZEND_ASSERT(EX(func) == (zend_function*)op_array);
2122
2123 EX(opline) = op_array->opcodes;
2124 EX(call) = NULL;
2125 EX(return_value) = return_value;
2126
2127 /* Handle arguments */
2128 first_extra_arg = op_array->num_args;
2129 num_args = EX_NUM_ARGS();
2130 if (UNEXPECTED(num_args > first_extra_arg)) {
2131 if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
2132 zval *end, *src, *dst;
2133 uint32_t type_flags = 0;
2134
2135 if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
2136 /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
2137 EX(opline) += first_extra_arg;
2138 }
2139
2140 /* move extra args into separate array after all CV and TMP vars */
2141 end = EX_VAR_NUM(first_extra_arg - 1);
2142 src = end + (num_args - first_extra_arg);
2143 dst = src + (op_array->last_var + op_array->T - first_extra_arg);
2144 if (EXPECTED(src != dst)) {
2145 do {
2146 type_flags |= Z_TYPE_INFO_P(src);
2147 ZVAL_COPY_VALUE(dst, src);
2148 ZVAL_UNDEF(src);
2149 src--;
2150 dst--;
2151 } while (src != end);
2152 } else {
2153 do {
2154 type_flags |= Z_TYPE_INFO_P(src);
2155 src--;
2156 } while (src != end);
2157 }
2158 ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
2159 }
2160 } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
2161 /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
2162 EX(opline) += num_args;
2163 }
2164
2165 /* Initialize CV variables (skip arguments) */
2166 if (EXPECTED((int)num_args < op_array->last_var)) {
2167 zval *var = EX_VAR_NUM(num_args);
2168 zval *end = EX_VAR_NUM(op_array->last_var);
2169
2170 do {
2171 ZVAL_UNDEF(var);
2172 var++;
2173 } while (var != end);
2174 }
2175
2176 if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
2177 ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
2178 GC_REFCOUNT(Z_OBJ(EX(This)))++;
2179 }
2180
2181 if (UNEXPECTED(!op_array->run_time_cache)) {
2182 op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
2183 memset(op_array->run_time_cache, 0, op_array->cache_size);
2184 }
2185 EX_LOAD_RUN_TIME_CACHE(op_array);
2186 EX_LOAD_LITERALS(op_array);
2187
2188 EG(current_execute_data) = execute_data;
2189 ZEND_VM_INTERRUPT_CHECK();
2190 }
2191 /* }}} */
2192
i_init_code_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value)2193 static zend_always_inline void i_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
2194 {
2195 ZEND_ASSERT(EX(func) == (zend_function*)op_array);
2196
2197 EX(opline) = op_array->opcodes;
2198 EX(call) = NULL;
2199 EX(return_value) = return_value;
2200
2201 if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_OBJ(EX(This)))) {
2202 GC_REFCOUNT(Z_OBJ(EX(This)))++;
2203 if (!zend_hash_str_add(EX(symbol_table), "this", sizeof("this")-1, &EX(This))) {
2204 GC_REFCOUNT(Z_OBJ(EX(This)))--;
2205 }
2206 }
2207
2208 zend_attach_symbol_table(execute_data);
2209
2210 if (!op_array->run_time_cache) {
2211 op_array->run_time_cache = emalloc(op_array->cache_size);
2212 memset(op_array->run_time_cache, 0, op_array->cache_size);
2213 }
2214 EX_LOAD_RUN_TIME_CACHE(op_array);
2215 EX_LOAD_LITERALS(op_array);
2216
2217 EG(current_execute_data) = execute_data;
2218 ZEND_VM_INTERRUPT_CHECK();
2219 }
2220 /* }}} */
2221
i_init_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value)2222 static zend_always_inline void i_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
2223 {
2224 ZEND_ASSERT(EX(func) == (zend_function*)op_array);
2225
2226 EX(opline) = op_array->opcodes;
2227 EX(call) = NULL;
2228 EX(return_value) = return_value;
2229
2230 if (UNEXPECTED(EX(symbol_table) != NULL)) {
2231 if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_OBJ(EX(This)))) {
2232 GC_REFCOUNT(Z_OBJ(EX(This)))++;
2233 if (!zend_hash_str_add(EX(symbol_table), "this", sizeof("this")-1, &EX(This))) {
2234 GC_REFCOUNT(Z_OBJ(EX(This)))--;
2235 }
2236 }
2237
2238 zend_attach_symbol_table(execute_data);
2239 } else {
2240 uint32_t first_extra_arg, num_args;
2241
2242 /* Handle arguments */
2243 first_extra_arg = op_array->num_args;
2244 num_args = EX_NUM_ARGS();
2245 if (UNEXPECTED(num_args > first_extra_arg)) {
2246 if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
2247 zval *end, *src, *dst;
2248 uint32_t type_flags = 0;
2249
2250 if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
2251 /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
2252 EX(opline) += first_extra_arg;
2253 }
2254
2255 /* move extra args into separate array after all CV and TMP vars */
2256 end = EX_VAR_NUM(first_extra_arg - 1);
2257 src = end + (num_args - first_extra_arg);
2258 dst = src + (op_array->last_var + op_array->T - first_extra_arg);
2259 if (EXPECTED(src != dst)) {
2260 do {
2261 type_flags |= Z_TYPE_INFO_P(src);
2262 ZVAL_COPY_VALUE(dst, src);
2263 ZVAL_UNDEF(src);
2264 src--;
2265 dst--;
2266 } while (src != end);
2267 } else {
2268 do {
2269 type_flags |= Z_TYPE_INFO_P(src);
2270 src--;
2271 } while (src != end);
2272 }
2273 ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
2274 }
2275 } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
2276 /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
2277 EX(opline) += num_args;
2278 }
2279
2280 /* Initialize CV variables (skip arguments) */
2281 if (EXPECTED((int)num_args < op_array->last_var)) {
2282 zval *var = EX_VAR_NUM(num_args);
2283 zval *end = EX_VAR_NUM(op_array->last_var);
2284
2285 do {
2286 ZVAL_UNDEF(var);
2287 var++;
2288 } while (var != end);
2289 }
2290
2291 if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
2292 ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
2293 GC_REFCOUNT(Z_OBJ(EX(This)))++;
2294 }
2295 }
2296
2297 if (!op_array->run_time_cache) {
2298 if (op_array->function_name) {
2299 op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
2300 } else {
2301 op_array->run_time_cache = emalloc(op_array->cache_size);
2302 }
2303 memset(op_array->run_time_cache, 0, op_array->cache_size);
2304 }
2305 EX_LOAD_RUN_TIME_CACHE(op_array);
2306 EX_LOAD_LITERALS(op_array);
2307
2308 EG(current_execute_data) = execute_data;
2309 ZEND_VM_INTERRUPT_CHECK();
2310 }
2311 /* }}} */
2312
zend_create_generator_execute_data(zend_execute_data * call,zend_op_array * op_array,zval * return_value)2313 ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value) /* {{{ */
2314 {
2315 /*
2316 * Normally the execute_data is allocated on the VM stack (because it does
2317 * not actually do any allocation and thus is faster). For generators
2318 * though this behavior would be suboptimal, because the (rather large)
2319 * structure would have to be copied back and forth every time execution is
2320 * suspended or resumed. That's why for generators the execution context
2321 * is allocated using a separate VM stack, thus allowing to save and
2322 * restore it simply by replacing a pointer.
2323 */
2324 zend_execute_data *execute_data;
2325 uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
2326 size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval);
2327 uint32_t call_info;
2328
2329 EG(vm_stack) = zend_vm_stack_new_page(
2330 EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE(1)) ?
2331 ZEND_VM_STACK_PAGE_SIZE(1) :
2332 ZEND_VM_STACK_PAGE_ALIGNED_SIZE(1, stack_size),
2333 NULL);
2334 EG(vm_stack_top) = EG(vm_stack)->top;
2335 EG(vm_stack_end) = EG(vm_stack)->end;
2336
2337 call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS));
2338 if (Z_OBJ(call->This)) {
2339 call_info |= ZEND_CALL_RELEASE_THIS;
2340 }
2341 execute_data = zend_vm_stack_push_call_frame(
2342 call_info,
2343 (zend_function*)op_array,
2344 num_args,
2345 call->called_scope,
2346 Z_OBJ(call->This));
2347 EX(prev_execute_data) = NULL;
2348 EX_NUM_ARGS() = num_args;
2349
2350 /* copy arguments */
2351 if (num_args > 0) {
2352 zval *arg_src = ZEND_CALL_ARG(call, 1);
2353 zval *arg_dst = ZEND_CALL_ARG(execute_data, 1);
2354 zval *end = arg_src + num_args;
2355
2356 do {
2357 ZVAL_COPY_VALUE(arg_dst, arg_src);
2358 arg_src++;
2359 arg_dst++;
2360 } while (arg_src != end);
2361 }
2362
2363 EX(symbol_table) = NULL;
2364
2365 i_init_func_execute_data(execute_data, op_array, return_value, 1);
2366
2367 return execute_data;
2368 }
2369 /* }}} */
2370
zend_init_execute_data(zend_execute_data * execute_data,zend_op_array * op_array,zval * return_value)2371 ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
2372 {
2373 EX(prev_execute_data) = EG(current_execute_data);
2374 i_init_execute_data(execute_data, op_array, return_value);
2375 }
2376 /* }}} */
2377
zend_is_by_ref_func_arg_fetch(const zend_op * opline,zend_execute_data * call)2378 static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(const zend_op *opline, zend_execute_data *call) /* {{{ */
2379 {
2380 uint32_t arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK;
2381 return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num);
2382 }
2383 /* }}} */
2384
zend_vm_stack_copy_call_frame(zend_execute_data * call,uint32_t passed_args,uint32_t additional_args)2385 static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, uint32_t passed_args, uint32_t additional_args) /* {{{ */
2386 {
2387 zend_execute_data *new_call;
2388 int used_stack = (EG(vm_stack_top) - (zval*)call) + additional_args;
2389
2390 /* copy call frame into new stack segment */
2391 new_call = zend_vm_stack_extend(used_stack * sizeof(zval));
2392 *new_call = *call;
2393 ZEND_SET_CALL_INFO(new_call, ZEND_CALL_INFO(new_call) | ZEND_CALL_ALLOCATED);
2394
2395 if (passed_args) {
2396 zval *src = ZEND_CALL_ARG(call, 1);
2397 zval *dst = ZEND_CALL_ARG(new_call, 1);
2398 do {
2399 ZVAL_COPY_VALUE(dst, src);
2400 passed_args--;
2401 src++;
2402 dst++;
2403 } while (passed_args);
2404 }
2405
2406 /* delete old call_frame from previous stack segment */
2407 EG(vm_stack)->prev->top = (zval*)call;
2408
2409 /* delete previous stack segment if it becames empty */
2410 if (UNEXPECTED(EG(vm_stack)->prev->top == ZEND_VM_STACK_ELEMETS(EG(vm_stack)->prev))) {
2411 zend_vm_stack r = EG(vm_stack)->prev;
2412
2413 EG(vm_stack)->prev = r->prev;
2414 efree(r);
2415 }
2416
2417 return new_call;
2418 }
2419 /* }}} */
2420
zend_vm_stack_extend_call_frame(zend_execute_data ** call,uint32_t passed_args,uint32_t additional_args)2421 static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, uint32_t passed_args, uint32_t additional_args) /* {{{ */
2422 {
2423 if (EXPECTED((uint32_t)(EG(vm_stack_end) - EG(vm_stack_top)) > additional_args)) {
2424 EG(vm_stack_top) += additional_args;
2425 } else {
2426 *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args);
2427 }
2428 }
2429 /* }}} */
2430
zend_get_running_generator(zend_execute_data * execute_data)2431 static zend_always_inline zend_generator *zend_get_running_generator(zend_execute_data *execute_data) /* {{{ */
2432 {
2433 /* The generator object is stored in EX(return_value) */
2434 zend_generator *generator = (zend_generator *) EX(return_value);
2435 /* However control may currently be delegated to another generator.
2436 * That's the one we're interested in. */
2437 return generator;
2438 }
2439 /* }}} */
2440
cleanup_unfinished_calls(zend_execute_data * execute_data,uint32_t op_num)2441 static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */
2442 {
2443 if (UNEXPECTED(EX(call))) {
2444 zend_execute_data *call = EX(call);
2445 zend_op *opline = EX(func)->op_array.opcodes + op_num;
2446 int level;
2447 int do_exit;
2448
2449 if (UNEXPECTED(opline->opcode == ZEND_INIT_FCALL ||
2450 opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
2451 opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
2452 opline->opcode == ZEND_INIT_DYNAMIC_CALL ||
2453 opline->opcode == ZEND_INIT_USER_CALL ||
2454 opline->opcode == ZEND_INIT_METHOD_CALL ||
2455 opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
2456 opline->opcode == ZEND_NEW)) {
2457 ZEND_ASSERT(op_num);
2458 opline--;
2459 }
2460
2461 do {
2462 /* If the exception was thrown during a function call there might be
2463 * arguments pushed to the stack that have to be dtor'ed. */
2464
2465 /* find the number of actually passed arguments */
2466 level = 0;
2467 do_exit = 0;
2468 do {
2469 switch (opline->opcode) {
2470 case ZEND_DO_FCALL:
2471 case ZEND_DO_ICALL:
2472 case ZEND_DO_UCALL:
2473 case ZEND_DO_FCALL_BY_NAME:
2474 level++;
2475 break;
2476 case ZEND_INIT_FCALL:
2477 case ZEND_INIT_FCALL_BY_NAME:
2478 case ZEND_INIT_NS_FCALL_BY_NAME:
2479 case ZEND_INIT_DYNAMIC_CALL:
2480 case ZEND_INIT_USER_CALL:
2481 case ZEND_INIT_METHOD_CALL:
2482 case ZEND_INIT_STATIC_METHOD_CALL:
2483 case ZEND_NEW:
2484 if (level == 0) {
2485 ZEND_CALL_NUM_ARGS(call) = 0;
2486 do_exit = 1;
2487 }
2488 level--;
2489 break;
2490 case ZEND_SEND_VAL:
2491 case ZEND_SEND_VAL_EX:
2492 case ZEND_SEND_VAR:
2493 case ZEND_SEND_VAR_EX:
2494 case ZEND_SEND_REF:
2495 case ZEND_SEND_VAR_NO_REF:
2496 case ZEND_SEND_USER:
2497 if (level == 0) {
2498 ZEND_CALL_NUM_ARGS(call) = opline->op2.num;
2499 do_exit = 1;
2500 }
2501 break;
2502 case ZEND_SEND_ARRAY:
2503 case ZEND_SEND_UNPACK:
2504 if (level == 0) {
2505 do_exit = 1;
2506 }
2507 break;
2508 }
2509 if (!do_exit) {
2510 opline--;
2511 }
2512 } while (!do_exit);
2513 if (call->prev_execute_data) {
2514 /* skip current call region */
2515 level = 0;
2516 do_exit = 0;
2517 do {
2518 switch (opline->opcode) {
2519 case ZEND_DO_FCALL:
2520 case ZEND_DO_ICALL:
2521 case ZEND_DO_UCALL:
2522 case ZEND_DO_FCALL_BY_NAME:
2523 level++;
2524 break;
2525 case ZEND_INIT_FCALL:
2526 case ZEND_INIT_FCALL_BY_NAME:
2527 case ZEND_INIT_NS_FCALL_BY_NAME:
2528 case ZEND_INIT_DYNAMIC_CALL:
2529 case ZEND_INIT_USER_CALL:
2530 case ZEND_INIT_METHOD_CALL:
2531 case ZEND_INIT_STATIC_METHOD_CALL:
2532 case ZEND_NEW:
2533 if (level == 0) {
2534 do_exit = 1;
2535 }
2536 level--;
2537 break;
2538 }
2539 opline--;
2540 } while (!do_exit);
2541 }
2542
2543 zend_vm_stack_free_args(EX(call));
2544
2545 if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
2546 if (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR) {
2547 if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) {
2548 GC_REFCOUNT(Z_OBJ(call->This))--;
2549 }
2550 if (GC_REFCOUNT(Z_OBJ(call->This)) == 1) {
2551 zend_object_store_ctor_failed(Z_OBJ(call->This));
2552 }
2553 }
2554 OBJ_RELEASE(Z_OBJ(call->This));
2555 }
2556 if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
2557 zend_object_release((zend_object *) call->func->common.prototype);
2558 } else if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2559 zend_string_release(call->func->common.function_name);
2560 zend_free_trampoline(call->func);
2561 }
2562
2563 EX(call) = call->prev_execute_data;
2564 zend_vm_stack_free_call_frame(call);
2565 call = EX(call);
2566 } while (call);
2567 }
2568 }
2569 /* }}} */
2570
cleanup_live_vars(zend_execute_data * execute_data,uint32_t op_num,uint32_t catch_op_num)2571 static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
2572 {
2573 int i;
2574
2575 for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) {
2576 const zend_brk_cont_element *brk_cont = &EX(func)->op_array.brk_cont_array[i];
2577 if (brk_cont->start < 0) {
2578 continue;
2579 } else if (brk_cont->start > op_num) {
2580 /* further blocks will not be relevant... */
2581 break;
2582 } else if (op_num < brk_cont->brk) {
2583 if (!catch_op_num || catch_op_num >= brk_cont->brk) {
2584 zend_op *brk_opline = &EX(func)->op_array.opcodes[brk_cont->brk];
2585
2586 if (brk_opline->opcode == ZEND_FREE) {
2587 zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
2588 } else if (brk_opline->opcode == ZEND_FE_FREE) {
2589 zval *var = EX_VAR(brk_opline->op1.var);
2590 if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
2591 zend_hash_iterator_del(Z_FE_ITER_P(var));
2592 }
2593 zval_ptr_dtor_nogc(var);
2594 } else if (brk_opline->opcode == ZEND_ROPE_END) {
2595 zend_string **rope = (zend_string **) EX_VAR(brk_opline->op1.var);
2596 zend_op *last = EX(func)->op_array.opcodes + op_num;
2597 while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT)
2598 || last->result.var != brk_opline->op1.var) {
2599 ZEND_ASSERT(last >= EX(func)->op_array.opcodes);
2600 last--;
2601 }
2602 if (last->opcode == ZEND_ROPE_INIT) {
2603 zend_string_release(*rope);
2604 } else {
2605 int j = last->extended_value;
2606 do {
2607 zend_string_release(rope[j]);
2608 } while (j--);
2609 }
2610 } else if (brk_opline->opcode == ZEND_END_SILENCE) {
2611 /* restore previous error_reporting value */
2612 if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
2613 EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var));
2614 }
2615 }
2616 }
2617 }
2618 }
2619 }
2620 /* }}} */
2621
zend_cleanup_unfinished_execution(zend_execute_data * execute_data,uint32_t op_num,uint32_t catch_op_num)2622 void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) {
2623 cleanup_unfinished_calls(execute_data, op_num);
2624 cleanup_live_vars(execute_data, op_num, catch_op_num);
2625 }
2626
2627 #ifdef HAVE_GCC_GLOBAL_REGS
2628 # if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
2629 # define ZEND_VM_FP_GLOBAL_REG "%esi"
2630 # define ZEND_VM_IP_GLOBAL_REG "%edi"
2631 # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
2632 # define ZEND_VM_FP_GLOBAL_REG "%r14"
2633 # define ZEND_VM_IP_GLOBAL_REG "%r15"
2634 # elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
2635 # define ZEND_VM_FP_GLOBAL_REG "r28"
2636 # define ZEND_VM_IP_GLOBAL_REG "r29"
2637 # elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
2638 # define ZEND_VM_FP_GLOBAL_REG "r28"
2639 # define ZEND_VM_IP_GLOBAL_REG "r29"
2640 # endif
2641 #endif
2642
2643 #define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
2644 CHECK_SYMBOL_TABLES() \
2645 if (check_exception) { \
2646 OPLINE = EX(opline) + (skip); \
2647 } else { \
2648 OPLINE = opline + (skip); \
2649 } \
2650 ZEND_VM_CONTINUE()
2651
2652 #define ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION() \
2653 ZEND_VM_NEXT_OPCODE_EX(1, 1)
2654
2655 #define ZEND_VM_NEXT_OPCODE() \
2656 ZEND_VM_NEXT_OPCODE_EX(0, 1)
2657
2658 #define ZEND_VM_SET_NEXT_OPCODE(new_op) \
2659 CHECK_SYMBOL_TABLES() \
2660 OPLINE = new_op
2661
2662 #define ZEND_VM_SET_OPCODE(new_op) \
2663 CHECK_SYMBOL_TABLES() \
2664 OPLINE = new_op; \
2665 ZEND_VM_INTERRUPT_CHECK()
2666
2667 #define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
2668 ZEND_VM_SET_OPCODE(ZEND_OFFSET_TO_OPLINE(opline, offset))
2669
2670 #define ZEND_VM_JMP(new_op) \
2671 if (EXPECTED(!EG(exception))) { \
2672 ZEND_VM_SET_OPCODE(new_op); \
2673 } else { \
2674 LOAD_OPLINE(); \
2675 } \
2676 ZEND_VM_CONTINUE()
2677
2678 #define ZEND_VM_INC_OPCODE() \
2679 OPLINE++
2680
2681
2682 #ifndef VM_SMART_OPCODES
2683 # define VM_SMART_OPCODES 1
2684 #endif
2685
2686 #if VM_SMART_OPCODES
2687 # define ZEND_VM_REPEATABLE_OPCODE \
2688 do {
2689 # define ZEND_VM_REPEAT_OPCODE(_opcode) \
2690 } while (UNEXPECTED((++opline)->opcode == _opcode)); \
2691 OPLINE = opline; \
2692 ZEND_VM_CONTINUE()
2693 # define ZEND_VM_SMART_BRANCH(_result, _check) do { \
2694 int __result; \
2695 if (EXPECTED((opline+1)->opcode == ZEND_JMPZ)) { \
2696 __result = (_result); \
2697 } else if (EXPECTED((opline+1)->opcode == ZEND_JMPNZ)) { \
2698 __result = !(_result); \
2699 } else { \
2700 break; \
2701 } \
2702 if ((_check) && UNEXPECTED(EG(exception))) { \
2703 HANDLE_EXCEPTION(); \
2704 } \
2705 if (__result) { \
2706 ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
2707 } else { \
2708 ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
2709 } \
2710 ZEND_VM_CONTINUE(); \
2711 } while (0)
2712 #else
2713 # define ZEND_VM_REPEATABLE_OPCODE
2714 # define ZEND_VM_REPEAT_OPCODE(_opcode)
2715 # define ZEND_VM_SMART_BRANCH(_result, _check)
2716 #endif
2717
2718 #ifdef __GNUC__
2719 # define ZEND_VM_GUARD(name) __asm__("#" #name)
2720 #else
2721 # define ZEND_VM_GUARD(name)
2722 #endif
2723
2724 #define GET_OP1_UNDEF_CV(ptr, type) \
2725 _get_zval_cv_lookup_ ## type(ptr, opline->op1.var, execute_data)
2726 #define GET_OP2_UNDEF_CV(ptr, type) \
2727 _get_zval_cv_lookup_ ## type(ptr, opline->op2.var, execute_data)
2728
2729 #include "zend_vm_execute.h"
2730
zend_set_user_opcode_handler(zend_uchar opcode,user_opcode_handler_t handler)2731 ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
2732 {
2733 if (opcode != ZEND_USER_OPCODE) {
2734 if (handler == NULL) {
2735 /* restore the original handler */
2736 zend_user_opcodes[opcode] = opcode;
2737 } else {
2738 zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
2739 }
2740 zend_user_opcode_handlers[opcode] = handler;
2741 return SUCCESS;
2742 }
2743 return FAILURE;
2744 }
2745
zend_get_user_opcode_handler(zend_uchar opcode)2746 ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
2747 {
2748 return zend_user_opcode_handlers[opcode];
2749 }
2750
zend_get_zval_ptr(int op_type,const znode_op * node,const zend_execute_data * execute_data,zend_free_op * should_free,int type)2751 ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type)
2752 {
2753 return get_zval_ptr(op_type, *node, execute_data, should_free, type);
2754 }
2755
zend_check_internal_arg_type(zend_function * zf,uint32_t arg_num,zval * arg)2756 ZEND_API void ZEND_FASTCALL zend_check_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg)
2757 {
2758 zend_verify_internal_arg_type(zf, arg_num, arg);
2759 }
2760
zend_check_arg_type(zend_function * zf,uint32_t arg_num,zval * arg,zval * default_value,void ** cache_slot)2761 ZEND_API int ZEND_FASTCALL zend_check_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
2762 {
2763 return zend_verify_arg_type(zf, arg_num, arg, default_value, cache_slot);
2764 }
2765
zend_check_missing_arg(zend_execute_data * execute_data,uint32_t arg_num,void ** cache_slot)2766 ZEND_API void ZEND_FASTCALL zend_check_missing_arg(zend_execute_data *execute_data, uint32_t arg_num, void **cache_slot)
2767 {
2768 zend_verify_missing_arg(execute_data, arg_num, cache_slot);
2769 }
2770
2771 /*
2772 * Local variables:
2773 * tab-width: 4
2774 * c-basic-offset: 4
2775 * indent-tabs-mode: t
2776 * End:
2777 */
2778