1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Nikita Popov <nikic@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include <zend_language_parser.h>
22 #include "zend.h"
23 #include "zend_ast.h"
24 #include "zend_attributes.h"
25 #include "zend_compile.h"
26 #include "zend_constants.h"
27 #include "zend_llist.h"
28 #include "zend_API.h"
29 #include "zend_exceptions.h"
30 #include "zend_interfaces.h"
31 #include "zend_virtual_cwd.h"
32 #include "zend_multibyte.h"
33 #include "zend_language_scanner.h"
34 #include "zend_inheritance.h"
35 #include "zend_vm.h"
36 #include "zend_enum.h"
37 #include "zend_observer.h"
38 #include "zend_call_stack.h"
39 #include "zend_frameless_function.h"
40 #include "zend_property_hooks.h"
41
42 #define SET_NODE(target, src) do { \
43 target ## _type = (src)->op_type; \
44 if ((src)->op_type == IS_CONST) { \
45 target.constant = zend_add_literal(&(src)->u.constant); \
46 } else { \
47 target = (src)->u.op; \
48 } \
49 } while (0)
50
51 #define GET_NODE(target, src) do { \
52 (target)->op_type = src ## _type; \
53 if ((target)->op_type == IS_CONST) { \
54 ZVAL_COPY_VALUE(&(target)->u.constant, CT_CONSTANT(src)); \
55 } else { \
56 (target)->u.op = src; \
57 } \
58 } while (0)
59
60 #define FC(member) (CG(file_context).member)
61
62 typedef struct _zend_loop_var {
63 uint8_t opcode;
64 uint8_t var_type;
65 uint32_t var_num;
66 uint32_t try_catch_offset;
67 } zend_loop_var;
68
zend_alloc_cache_slots(unsigned count)69 static inline uint32_t zend_alloc_cache_slots(unsigned count) {
70 if (count == 0) {
71 /* Even if no cache slots are desired, the VM handler may still want to acquire
72 * CACHE_ADDR() unconditionally. Returning zero makes sure that the address
73 * calculation is still legal and ubsan does not complain. */
74 return 0;
75 }
76
77 zend_op_array *op_array = CG(active_op_array);
78 uint32_t ret = op_array->cache_size;
79 op_array->cache_size += count * sizeof(void*);
80 return ret;
81 }
82
zend_alloc_cache_slot(void)83 static inline uint32_t zend_alloc_cache_slot(void) {
84 return zend_alloc_cache_slots(1);
85 }
86
87 ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type);
88 ZEND_API zend_op_array *(*zend_compile_string)(zend_string *source_string, const char *filename, zend_compile_position position);
89
90 #ifndef ZTS
91 ZEND_API zend_compiler_globals compiler_globals;
92 ZEND_API zend_executor_globals executor_globals;
93 #endif
94
95 static zend_op *zend_emit_op(znode *result, uint8_t opcode, znode *op1, znode *op2);
96 static bool zend_try_ct_eval_array(zval *result, zend_ast *ast);
97 static void zend_eval_const_expr(zend_ast **ast_ptr);
98
99 static zend_op *zend_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref);
100 static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref);
101 static void zend_compile_expr(znode *result, zend_ast *ast);
102 static void zend_compile_stmt(zend_ast *ast);
103 static void zend_compile_assign(znode *result, zend_ast *ast);
104
105 #ifdef ZEND_CHECK_STACK_LIMIT
zend_stack_limit_error(void)106 zend_never_inline static void zend_stack_limit_error(void)
107 {
108 size_t max_stack_size = 0;
109 if ((uintptr_t) EG(stack_base) > (uintptr_t) EG(stack_limit)) {
110 max_stack_size = (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit));
111 }
112
113 zend_error_noreturn(E_COMPILE_ERROR,
114 "Maximum call stack size of %zu bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached during compilation. Try splitting expression",
115 max_stack_size);
116 }
117
zend_check_stack_limit(void)118 static void zend_check_stack_limit(void)
119 {
120 if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) {
121 zend_stack_limit_error();
122 }
123 }
124 #else /* ZEND_CHECK_STACK_LIMIT */
zend_check_stack_limit(void)125 static void zend_check_stack_limit(void)
126 {
127 }
128 #endif /* ZEND_CHECK_STACK_LIMIT */
129
init_op(zend_op * op)130 static void init_op(zend_op *op)
131 {
132 MAKE_NOP(op);
133 op->extended_value = 0;
134 op->lineno = CG(zend_lineno);
135 #ifdef ZEND_VERIFY_TYPE_INFERENCE
136 op->op1_use_type = 0;
137 op->op2_use_type = 0;
138 op->result_use_type = 0;
139 op->op1_def_type = 0;
140 op->op2_def_type = 0;
141 op->result_def_type = 0;
142 #endif
143 }
144
get_next_op_number(void)145 static zend_always_inline uint32_t get_next_op_number(void)
146 {
147 return CG(active_op_array)->last;
148 }
149
get_next_op(void)150 static zend_op *get_next_op(void)
151 {
152 zend_op_array *op_array = CG(active_op_array);
153 uint32_t next_op_num = op_array->last++;
154 zend_op *next_op;
155
156 if (UNEXPECTED(next_op_num >= CG(context).opcodes_size)) {
157 CG(context).opcodes_size *= 4;
158 op_array->opcodes = erealloc(op_array->opcodes, CG(context).opcodes_size * sizeof(zend_op));
159 }
160
161 next_op = &(op_array->opcodes[next_op_num]);
162
163 init_op(next_op);
164
165 return next_op;
166 }
167
get_next_brk_cont_element(void)168 static zend_brk_cont_element *get_next_brk_cont_element(void)
169 {
170 CG(context).last_brk_cont++;
171 CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element) * CG(context).last_brk_cont);
172 return &CG(context).brk_cont_array[CG(context).last_brk_cont-1];
173 }
174
zend_build_runtime_definition_key(zend_string * name,uint32_t start_lineno)175 static zend_string *zend_build_runtime_definition_key(zend_string *name, uint32_t start_lineno) /* {{{ */
176 {
177 zend_string *filename = CG(active_op_array)->filename;
178 zend_string *result = zend_strpprintf(0, "%c%s%s:%" PRIu32 "$%" PRIx32,
179 '\0', ZSTR_VAL(name), ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
180 return zend_new_interned_string(result);
181 }
182 /* }}} */
183
zend_get_unqualified_name(const zend_string * name,const char ** result,size_t * result_len)184 static bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len) /* {{{ */
185 {
186 const char *ns_separator = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
187 if (ns_separator != NULL) {
188 *result = ns_separator + 1;
189 *result_len = ZSTR_VAL(name) + ZSTR_LEN(name) - *result;
190 return 1;
191 }
192
193 return 0;
194 }
195 /* }}} */
196
197 struct reserved_class_name {
198 const char *name;
199 size_t len;
200 };
201 static const struct reserved_class_name reserved_class_names[] = {
202 {ZEND_STRL("bool")},
203 {ZEND_STRL("false")},
204 {ZEND_STRL("float")},
205 {ZEND_STRL("int")},
206 {ZEND_STRL("null")},
207 {ZEND_STRL("parent")},
208 {ZEND_STRL("self")},
209 {ZEND_STRL("static")},
210 {ZEND_STRL("string")},
211 {ZEND_STRL("true")},
212 {ZEND_STRL("void")},
213 {ZEND_STRL("never")},
214 {ZEND_STRL("iterable")},
215 {ZEND_STRL("object")},
216 {ZEND_STRL("mixed")},
217 {NULL, 0}
218 };
219
zend_is_reserved_class_name(const zend_string * name)220 static bool zend_is_reserved_class_name(const zend_string *name) /* {{{ */
221 {
222 const struct reserved_class_name *reserved = reserved_class_names;
223
224 const char *uqname = ZSTR_VAL(name);
225 size_t uqname_len = ZSTR_LEN(name);
226 zend_get_unqualified_name(name, &uqname, &uqname_len);
227
228 for (; reserved->name; ++reserved) {
229 if (uqname_len == reserved->len
230 && zend_binary_strcasecmp(uqname, uqname_len, reserved->name, reserved->len) == 0
231 ) {
232 return 1;
233 }
234 }
235
236 return 0;
237 }
238 /* }}} */
239
zend_assert_valid_class_name(const zend_string * name,const char * type)240 void zend_assert_valid_class_name(const zend_string *name, const char *type) /* {{{ */
241 {
242 if (zend_is_reserved_class_name(name)) {
243 zend_error_noreturn(E_COMPILE_ERROR,
244 "Cannot use \"%s\" as %s as it is reserved", ZSTR_VAL(name), type);
245 }
246 if (zend_string_equals_literal(name, "_")) {
247 zend_error(E_DEPRECATED, "Using \"_\" as %s is deprecated since 8.4", type);
248 }
249 }
250 /* }}} */
251
252 typedef struct _builtin_type_info {
253 const char* name;
254 const size_t name_len;
255 const uint8_t type;
256 } builtin_type_info;
257
258 static const builtin_type_info builtin_types[] = {
259 {ZEND_STRL("null"), IS_NULL},
260 {ZEND_STRL("true"), IS_TRUE},
261 {ZEND_STRL("false"), IS_FALSE},
262 {ZEND_STRL("int"), IS_LONG},
263 {ZEND_STRL("float"), IS_DOUBLE},
264 {ZEND_STRL("string"), IS_STRING},
265 {ZEND_STRL("bool"), _IS_BOOL},
266 {ZEND_STRL("void"), IS_VOID},
267 {ZEND_STRL("never"), IS_NEVER},
268 {ZEND_STRL("iterable"), IS_ITERABLE},
269 {ZEND_STRL("object"), IS_OBJECT},
270 {ZEND_STRL("mixed"), IS_MIXED},
271 {NULL, 0, IS_UNDEF}
272 };
273
274 typedef struct {
275 const char *name;
276 size_t name_len;
277 const char *correct_name;
278 } confusable_type_info;
279
280 static const confusable_type_info confusable_types[] = {
281 {ZEND_STRL("boolean"), "bool"},
282 {ZEND_STRL("integer"), "int"},
283 {ZEND_STRL("double"), "float"},
284 {ZEND_STRL("resource"), NULL},
285 {NULL, 0, NULL},
286 };
287
zend_lookup_builtin_type_by_name(const zend_string * name)288 static zend_always_inline uint8_t zend_lookup_builtin_type_by_name(const zend_string *name) /* {{{ */
289 {
290 const builtin_type_info *info = &builtin_types[0];
291
292 for (; info->name; ++info) {
293 if (ZSTR_LEN(name) == info->name_len
294 && zend_binary_strcasecmp(ZSTR_VAL(name), ZSTR_LEN(name), info->name, info->name_len) == 0
295 ) {
296 return info->type;
297 }
298 }
299
300 return 0;
301 }
302 /* }}} */
303
zend_is_confusable_type(const zend_string * name,const char ** correct_name)304 static zend_always_inline bool zend_is_confusable_type(const zend_string *name, const char **correct_name) /* {{{ */
305 {
306 const confusable_type_info *info = confusable_types;
307
308 /* Intentionally using case-sensitive comparison here, because "integer" is likely intended
309 * as a scalar type, while "Integer" is likely a class type. */
310 for (; info->name; ++info) {
311 if (zend_string_equals_cstr(name, info->name, info->name_len)) {
312 *correct_name = info->correct_name;
313 return 1;
314 }
315 }
316
317 return 0;
318 }
319 /* }}} */
320
zend_is_not_imported(zend_string * name)321 static bool zend_is_not_imported(zend_string *name) {
322 /* Assuming "name" is unqualified here. */
323 return !FC(imports) || zend_hash_find_ptr_lc(FC(imports), name) == NULL;
324 }
325
zend_oparray_context_begin(zend_oparray_context * prev_context,zend_op_array * op_array)326 void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_array *op_array) /* {{{ */
327 {
328 *prev_context = CG(context);
329 CG(context).prev = CG(context).op_array ? prev_context : NULL;
330 CG(context).op_array = op_array;
331 CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
332 CG(context).vars_size = 0;
333 CG(context).literals_size = 0;
334 CG(context).fast_call_var = -1;
335 CG(context).try_catch_offset = -1;
336 CG(context).current_brk_cont = -1;
337 CG(context).last_brk_cont = 0;
338 CG(context).brk_cont_array = NULL;
339 CG(context).labels = NULL;
340 CG(context).in_jmp_frameless_branch = false;
341 CG(context).active_property_info = NULL;
342 CG(context).active_property_hook_kind = (zend_property_hook_kind)-1;
343 }
344 /* }}} */
345
zend_oparray_context_end(zend_oparray_context * prev_context)346 void zend_oparray_context_end(zend_oparray_context *prev_context) /* {{{ */
347 {
348 if (CG(context).brk_cont_array) {
349 efree(CG(context).brk_cont_array);
350 CG(context).brk_cont_array = NULL;
351 }
352 if (CG(context).labels) {
353 zend_hash_destroy(CG(context).labels);
354 FREE_HASHTABLE(CG(context).labels);
355 CG(context).labels = NULL;
356 }
357 CG(context) = *prev_context;
358 }
359 /* }}} */
360
zend_reset_import_tables(void)361 static void zend_reset_import_tables(void) /* {{{ */
362 {
363 if (FC(imports)) {
364 zend_hash_destroy(FC(imports));
365 efree(FC(imports));
366 FC(imports) = NULL;
367 }
368
369 if (FC(imports_function)) {
370 zend_hash_destroy(FC(imports_function));
371 efree(FC(imports_function));
372 FC(imports_function) = NULL;
373 }
374
375 if (FC(imports_const)) {
376 zend_hash_destroy(FC(imports_const));
377 efree(FC(imports_const));
378 FC(imports_const) = NULL;
379 }
380
381 zend_hash_clean(&FC(seen_symbols));
382 }
383 /* }}} */
384
zend_end_namespace(void)385 static void zend_end_namespace(void) /* {{{ */ {
386 FC(in_namespace) = 0;
387 zend_reset_import_tables();
388 if (FC(current_namespace)) {
389 zend_string_release_ex(FC(current_namespace), 0);
390 FC(current_namespace) = NULL;
391 }
392 }
393 /* }}} */
394
zend_file_context_begin(zend_file_context * prev_context)395 void zend_file_context_begin(zend_file_context *prev_context) /* {{{ */
396 {
397 *prev_context = CG(file_context);
398 FC(imports) = NULL;
399 FC(imports_function) = NULL;
400 FC(imports_const) = NULL;
401 FC(current_namespace) = NULL;
402 FC(in_namespace) = 0;
403 FC(has_bracketed_namespaces) = 0;
404 FC(declarables).ticks = 0;
405 zend_hash_init(&FC(seen_symbols), 8, NULL, NULL, 0);
406 }
407 /* }}} */
408
zend_file_context_end(zend_file_context * prev_context)409 void zend_file_context_end(zend_file_context *prev_context) /* {{{ */
410 {
411 zend_end_namespace();
412 zend_hash_destroy(&FC(seen_symbols));
413 CG(file_context) = *prev_context;
414 }
415 /* }}} */
416
zend_init_compiler_data_structures(void)417 void zend_init_compiler_data_structures(void) /* {{{ */
418 {
419 zend_stack_init(&CG(loop_var_stack), sizeof(zend_loop_var));
420 zend_stack_init(&CG(delayed_oplines_stack), sizeof(zend_op));
421 zend_stack_init(&CG(short_circuiting_opnums), sizeof(uint32_t));
422 CG(active_class_entry) = NULL;
423 CG(in_compilation) = 0;
424 CG(skip_shebang) = 0;
425
426 CG(encoding_declared) = 0;
427 CG(memoized_exprs) = NULL;
428 CG(memoize_mode) = ZEND_MEMOIZE_NONE;
429 }
430 /* }}} */
431
zend_register_seen_symbol(zend_string * name,uint32_t kind)432 static void zend_register_seen_symbol(zend_string *name, uint32_t kind) {
433 zval *zv = zend_hash_find(&FC(seen_symbols), name);
434 if (zv) {
435 Z_LVAL_P(zv) |= kind;
436 } else {
437 zval tmp;
438 ZVAL_LONG(&tmp, kind);
439 zend_hash_add_new(&FC(seen_symbols), name, &tmp);
440 }
441 }
442
zend_have_seen_symbol(zend_string * name,uint32_t kind)443 static bool zend_have_seen_symbol(zend_string *name, uint32_t kind) {
444 zval *zv = zend_hash_find(&FC(seen_symbols), name);
445 return zv && (Z_LVAL_P(zv) & kind) != 0;
446 }
447
init_compiler(void)448 void init_compiler(void) /* {{{ */
449 {
450 CG(arena) = zend_arena_create(64 * 1024);
451 CG(active_op_array) = NULL;
452 memset(&CG(context), 0, sizeof(CG(context)));
453 zend_init_compiler_data_structures();
454 zend_init_rsrc_list();
455 zend_stream_init();
456 CG(unclean_shutdown) = 0;
457
458 CG(delayed_variance_obligations) = NULL;
459 CG(delayed_autoloads) = NULL;
460 CG(unlinked_uses) = NULL;
461 CG(current_linking_class) = NULL;
462 }
463 /* }}} */
464
shutdown_compiler(void)465 void shutdown_compiler(void) /* {{{ */
466 {
467 /* Reset filename before destroying the arena, as file cache may use arena allocated strings. */
468 zend_restore_compiled_filename(NULL);
469
470 zend_stack_destroy(&CG(loop_var_stack));
471 zend_stack_destroy(&CG(delayed_oplines_stack));
472 zend_stack_destroy(&CG(short_circuiting_opnums));
473
474 if (CG(delayed_variance_obligations)) {
475 zend_hash_destroy(CG(delayed_variance_obligations));
476 FREE_HASHTABLE(CG(delayed_variance_obligations));
477 CG(delayed_variance_obligations) = NULL;
478 }
479 if (CG(delayed_autoloads)) {
480 zend_hash_destroy(CG(delayed_autoloads));
481 FREE_HASHTABLE(CG(delayed_autoloads));
482 CG(delayed_autoloads) = NULL;
483 }
484 if (CG(unlinked_uses)) {
485 zend_hash_destroy(CG(unlinked_uses));
486 FREE_HASHTABLE(CG(unlinked_uses));
487 CG(unlinked_uses) = NULL;
488 }
489 CG(current_linking_class) = NULL;
490 }
491 /* }}} */
492
zend_set_compiled_filename(zend_string * new_compiled_filename)493 ZEND_API zend_string *zend_set_compiled_filename(zend_string *new_compiled_filename) /* {{{ */
494 {
495 CG(compiled_filename) = zend_string_copy(new_compiled_filename);
496 return new_compiled_filename;
497 }
498 /* }}} */
499
zend_restore_compiled_filename(zend_string * original_compiled_filename)500 ZEND_API void zend_restore_compiled_filename(zend_string *original_compiled_filename) /* {{{ */
501 {
502 if (CG(compiled_filename)) {
503 zend_string_release(CG(compiled_filename));
504 CG(compiled_filename) = NULL;
505 }
506 CG(compiled_filename) = original_compiled_filename;
507 }
508 /* }}} */
509
zend_get_compiled_filename(void)510 ZEND_API zend_string *zend_get_compiled_filename(void) /* {{{ */
511 {
512 return CG(compiled_filename);
513 }
514 /* }}} */
515
zend_get_compiled_lineno(void)516 ZEND_API int zend_get_compiled_lineno(void) /* {{{ */
517 {
518 return CG(zend_lineno);
519 }
520 /* }}} */
521
zend_is_compiling(void)522 ZEND_API bool zend_is_compiling(void) /* {{{ */
523 {
524 return CG(in_compilation);
525 }
526 /* }}} */
527
get_temporary_variable(void)528 static zend_always_inline uint32_t get_temporary_variable(void) /* {{{ */
529 {
530 return (uint32_t)CG(active_op_array)->T++;
531 }
532 /* }}} */
533
lookup_cv(zend_string * name)534 static int lookup_cv(zend_string *name) /* {{{ */{
535 zend_op_array *op_array = CG(active_op_array);
536 int i = 0;
537 zend_ulong hash_value = zend_string_hash_val(name);
538
539 while (i < op_array->last_var) {
540 if (ZSTR_H(op_array->vars[i]) == hash_value
541 && zend_string_equals(op_array->vars[i], name)) {
542 return EX_NUM_TO_VAR(i);
543 }
544 i++;
545 }
546 i = op_array->last_var;
547 op_array->last_var++;
548 if (op_array->last_var > CG(context).vars_size) {
549 CG(context).vars_size += 16; /* FIXME */
550 op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_string*));
551 }
552
553 op_array->vars[i] = zend_string_copy(name);
554 return EX_NUM_TO_VAR(i);
555 }
556 /* }}} */
557
zval_make_interned_string(zval * zv)558 zend_string *zval_make_interned_string(zval *zv)
559 {
560 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
561 Z_STR_P(zv) = zend_new_interned_string(Z_STR_P(zv));
562 if (ZSTR_IS_INTERNED(Z_STR_P(zv))) {
563 Z_TYPE_FLAGS_P(zv) = 0;
564 }
565 return Z_STR_P(zv);
566 }
567
568 /* Common part of zend_add_literal and zend_append_individual_literal */
zend_insert_literal(zend_op_array * op_array,zval * zv,int literal_position)569 static inline void zend_insert_literal(zend_op_array *op_array, zval *zv, int literal_position) /* {{{ */
570 {
571 zval *lit = CT_CONSTANT_EX(op_array, literal_position);
572 if (Z_TYPE_P(zv) == IS_STRING) {
573 zval_make_interned_string(zv);
574 }
575 ZVAL_COPY_VALUE(lit, zv);
576 Z_EXTRA_P(lit) = 0;
577 }
578 /* }}} */
579
580 /* Is used while compiling a function, using the context to keep track
581 of an approximate size to avoid to relocate to often.
582 Literals are truncated to actual size in the second compiler pass (pass_two()). */
zend_add_literal(zval * zv)583 static int zend_add_literal(zval *zv) /* {{{ */
584 {
585 zend_op_array *op_array = CG(active_op_array);
586 int i = op_array->last_literal;
587 op_array->last_literal++;
588 if (i >= CG(context).literals_size) {
589 while (i >= CG(context).literals_size) {
590 CG(context).literals_size += 16; /* FIXME */
591 }
592 op_array->literals = (zval*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zval));
593 }
594 zend_insert_literal(op_array, zv, i);
595 return i;
596 }
597 /* }}} */
598
zend_add_literal_string(zend_string ** str)599 static inline int zend_add_literal_string(zend_string **str) /* {{{ */
600 {
601 int ret;
602 zval zv;
603 ZVAL_STR(&zv, *str);
604 ret = zend_add_literal(&zv);
605 *str = Z_STR(zv);
606 return ret;
607 }
608 /* }}} */
609
zend_add_func_name_literal(zend_string * name)610 static int zend_add_func_name_literal(zend_string *name) /* {{{ */
611 {
612 /* Original name */
613 int ret = zend_add_literal_string(&name);
614
615 /* Lowercased name */
616 zend_string *lc_name = zend_string_tolower(name);
617 zend_add_literal_string(&lc_name);
618
619 return ret;
620 }
621 /* }}} */
622
zend_add_ns_func_name_literal(zend_string * name)623 static int zend_add_ns_func_name_literal(zend_string *name) /* {{{ */
624 {
625 const char *unqualified_name;
626 size_t unqualified_name_len;
627
628 /* Original name */
629 int ret = zend_add_literal_string(&name);
630
631 /* Lowercased name */
632 zend_string *lc_name = zend_string_tolower(name);
633 zend_add_literal_string(&lc_name);
634
635 /* Lowercased unqualified name */
636 if (zend_get_unqualified_name(name, &unqualified_name, &unqualified_name_len)) {
637 lc_name = zend_string_alloc(unqualified_name_len, 0);
638 zend_str_tolower_copy(ZSTR_VAL(lc_name), unqualified_name, unqualified_name_len);
639 zend_add_literal_string(&lc_name);
640 }
641
642 return ret;
643 }
644 /* }}} */
645
zend_add_class_name_literal(zend_string * name)646 static int zend_add_class_name_literal(zend_string *name) /* {{{ */
647 {
648 /* Original name */
649 int ret = zend_add_literal_string(&name);
650
651 /* Lowercased name */
652 zend_string *lc_name = zend_string_tolower(name);
653 zend_add_literal_string(&lc_name);
654
655 return ret;
656 }
657 /* }}} */
658
zend_add_const_name_literal(zend_string * name,bool unqualified)659 static int zend_add_const_name_literal(zend_string *name, bool unqualified) /* {{{ */
660 {
661 zend_string *tmp_name;
662
663 int ret = zend_add_literal_string(&name);
664
665 size_t ns_len = 0, after_ns_len = ZSTR_LEN(name);
666 const char *after_ns = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
667 if (after_ns) {
668 after_ns += 1;
669 ns_len = after_ns - ZSTR_VAL(name) - 1;
670 after_ns_len = ZSTR_LEN(name) - ns_len - 1;
671
672 /* lowercased namespace name & original constant name */
673 tmp_name = zend_string_init(ZSTR_VAL(name), ZSTR_LEN(name), 0);
674 zend_str_tolower(ZSTR_VAL(tmp_name), ns_len);
675 zend_add_literal_string(&tmp_name);
676
677 if (!unqualified) {
678 return ret;
679 }
680 } else {
681 after_ns = ZSTR_VAL(name);
682 }
683
684 /* original unqualified constant name */
685 tmp_name = zend_string_init(after_ns, after_ns_len, 0);
686 zend_add_literal_string(&tmp_name);
687
688 return ret;
689 }
690 /* }}} */
691
692 #define LITERAL_STR(op, str) do { \
693 zval _c; \
694 ZVAL_STR(&_c, str); \
695 op.constant = zend_add_literal(&_c); \
696 } while (0)
697
zend_stop_lexing(void)698 void zend_stop_lexing(void)
699 {
700 if (LANG_SCNG(on_event)) {
701 LANG_SCNG(on_event)(ON_STOP, END, 0, NULL, 0, LANG_SCNG(on_event_context));
702 }
703
704 LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);
705 }
706
zend_begin_loop(uint8_t free_opcode,const znode * loop_var,bool is_switch)707 static inline void zend_begin_loop(
708 uint8_t free_opcode, const znode *loop_var, bool is_switch) /* {{{ */
709 {
710 zend_brk_cont_element *brk_cont_element;
711 int parent = CG(context).current_brk_cont;
712 zend_loop_var info = {0};
713
714 CG(context).current_brk_cont = CG(context).last_brk_cont;
715 brk_cont_element = get_next_brk_cont_element();
716 brk_cont_element->parent = parent;
717 brk_cont_element->is_switch = is_switch;
718
719 if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) {
720 uint32_t start = get_next_op_number();
721
722 info.opcode = free_opcode;
723 info.var_type = loop_var->op_type;
724 info.var_num = loop_var->u.op.var;
725 brk_cont_element->start = start;
726 } else {
727 info.opcode = ZEND_NOP;
728 /* The start field is used to free temporary variables in case of exceptions.
729 * We won't try to free something of we don't have loop variable. */
730 brk_cont_element->start = -1;
731 }
732
733 zend_stack_push(&CG(loop_var_stack), &info);
734 }
735 /* }}} */
736
zend_end_loop(int cont_addr,const znode * var_node)737 static inline void zend_end_loop(int cont_addr, const znode *var_node) /* {{{ */
738 {
739 uint32_t end = get_next_op_number();
740 zend_brk_cont_element *brk_cont_element
741 = &CG(context).brk_cont_array[CG(context).current_brk_cont];
742 brk_cont_element->cont = cont_addr;
743 brk_cont_element->brk = end;
744 CG(context).current_brk_cont = brk_cont_element->parent;
745
746 zend_stack_del_top(&CG(loop_var_stack));
747 }
748 /* }}} */
749
zend_do_free(znode * op1)750 static void zend_do_free(znode *op1) /* {{{ */
751 {
752 if (op1->op_type == IS_TMP_VAR) {
753 zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
754
755 while (opline->opcode == ZEND_END_SILENCE ||
756 opline->opcode == ZEND_OP_DATA) {
757 opline--;
758 }
759
760 if (opline->result_type == IS_TMP_VAR && opline->result.var == op1->u.op.var) {
761 switch (opline->opcode) {
762 case ZEND_BOOL:
763 case ZEND_BOOL_NOT:
764 /* boolean results don't have to be freed */
765 return;
766 case ZEND_POST_INC_STATIC_PROP:
767 case ZEND_POST_DEC_STATIC_PROP:
768 case ZEND_POST_INC_OBJ:
769 case ZEND_POST_DEC_OBJ:
770 case ZEND_POST_INC:
771 case ZEND_POST_DEC:
772 /* convert $i++ to ++$i */
773 opline->opcode -= 2;
774 SET_UNUSED(opline->result);
775 return;
776 case ZEND_ASSIGN:
777 case ZEND_ASSIGN_DIM:
778 case ZEND_ASSIGN_OBJ:
779 case ZEND_ASSIGN_STATIC_PROP:
780 case ZEND_ASSIGN_OP:
781 case ZEND_ASSIGN_DIM_OP:
782 case ZEND_ASSIGN_OBJ_OP:
783 case ZEND_ASSIGN_STATIC_PROP_OP:
784 case ZEND_PRE_INC_STATIC_PROP:
785 case ZEND_PRE_DEC_STATIC_PROP:
786 case ZEND_PRE_INC_OBJ:
787 case ZEND_PRE_DEC_OBJ:
788 case ZEND_PRE_INC:
789 case ZEND_PRE_DEC:
790 SET_UNUSED(opline->result);
791 return;
792 }
793 }
794
795 zend_emit_op(NULL, ZEND_FREE, op1, NULL);
796 } else if (op1->op_type == IS_VAR) {
797 zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
798 while (opline->opcode == ZEND_END_SILENCE ||
799 opline->opcode == ZEND_EXT_FCALL_END ||
800 opline->opcode == ZEND_OP_DATA) {
801 opline--;
802 }
803 if (opline->result_type == IS_VAR
804 && opline->result.var == op1->u.op.var) {
805 if (opline->opcode == ZEND_FETCH_THIS) {
806 opline->opcode = ZEND_NOP;
807 }
808 if (!ZEND_OP_IS_FRAMELESS_ICALL(opline->opcode)) {
809 SET_UNUSED(opline->result);
810 } else {
811 /* Frameless calls usually use the return value, so always emit a free. This should be
812 * faster than checking RETURN_VALUE_USED inside the handler. */
813 // FIXME: We may actually look at the function signature to determine whether a free
814 // is necessary.
815 zend_emit_op(NULL, ZEND_FREE, op1, NULL);
816 }
817 } else {
818 while (opline >= CG(active_op_array)->opcodes) {
819 if ((opline->opcode == ZEND_FETCH_LIST_R ||
820 opline->opcode == ZEND_FETCH_LIST_W) &&
821 opline->op1_type == IS_VAR &&
822 opline->op1.var == op1->u.op.var) {
823 zend_emit_op(NULL, ZEND_FREE, op1, NULL);
824 return;
825 }
826 if (opline->result_type == IS_VAR
827 && opline->result.var == op1->u.op.var) {
828 if (opline->opcode == ZEND_NEW) {
829 zend_emit_op(NULL, ZEND_FREE, op1, NULL);
830 }
831 break;
832 }
833 opline--;
834 }
835 }
836 } else if (op1->op_type == IS_CONST) {
837 /* Destroy value without using GC: When opcache moves arrays into SHM it will
838 * free the zend_array structure, so references to it from outside the op array
839 * become invalid. GC would cause such a reference in the root buffer. */
840 zval_ptr_dtor_nogc(&op1->u.constant);
841 }
842 }
843 /* }}} */
844
845
zend_modifier_token_to_string(uint32_t token)846 static char *zend_modifier_token_to_string(uint32_t token)
847 {
848 switch (token) {
849 case T_PUBLIC:
850 return "public";
851 case T_PROTECTED:
852 return "protected";
853 case T_PRIVATE:
854 return "private";
855 case T_STATIC:
856 return "static";
857 case T_FINAL:
858 return "final";
859 case T_READONLY:
860 return "readonly";
861 case T_ABSTRACT:
862 return "abstract";
863 case T_PUBLIC_SET:
864 return "public(set)";
865 case T_PROTECTED_SET:
866 return "protected(set)";
867 case T_PRIVATE_SET:
868 return "private(set)";
869 EMPTY_SWITCH_DEFAULT_CASE()
870 }
871 }
872
zend_modifier_token_to_flag(zend_modifier_target target,uint32_t token)873 uint32_t zend_modifier_token_to_flag(zend_modifier_target target, uint32_t token)
874 {
875 switch (token) {
876 case T_PUBLIC:
877 if (target != ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
878 return ZEND_ACC_PUBLIC;
879 }
880 break;
881 case T_PROTECTED:
882 if (target != ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
883 return ZEND_ACC_PROTECTED;
884 }
885 break;
886 case T_PRIVATE:
887 if (target != ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
888 return ZEND_ACC_PRIVATE;
889 }
890 break;
891 case T_READONLY:
892 if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_CPP) {
893 return ZEND_ACC_READONLY;
894 }
895 break;
896 case T_ABSTRACT:
897 if (target == ZEND_MODIFIER_TARGET_METHOD || target == ZEND_MODIFIER_TARGET_PROPERTY) {
898 return ZEND_ACC_ABSTRACT;
899 }
900 break;
901 case T_FINAL:
902 if (target == ZEND_MODIFIER_TARGET_METHOD
903 || target == ZEND_MODIFIER_TARGET_CONSTANT
904 || target == ZEND_MODIFIER_TARGET_PROPERTY
905 || target == ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
906 return ZEND_ACC_FINAL;
907 }
908 break;
909 case T_STATIC:
910 if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_METHOD) {
911 return ZEND_ACC_STATIC;
912 }
913 break;
914 case T_PUBLIC_SET:
915 if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_CPP) {
916 return ZEND_ACC_PUBLIC_SET;
917 }
918 break;
919 case T_PROTECTED_SET:
920 if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_CPP) {
921 return ZEND_ACC_PROTECTED_SET;
922 }
923 break;
924 case T_PRIVATE_SET:
925 if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_CPP) {
926 return ZEND_ACC_PRIVATE_SET;
927 }
928 break;
929 }
930
931 char *member;
932 if (target == ZEND_MODIFIER_TARGET_PROPERTY) {
933 member = "property";
934 } else if (target == ZEND_MODIFIER_TARGET_METHOD) {
935 member = "method";
936 } else if (target == ZEND_MODIFIER_TARGET_CONSTANT) {
937 member = "class constant";
938 } else if (target == ZEND_MODIFIER_TARGET_CPP) {
939 member = "parameter";
940 } else if (target == ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
941 member = "property hook";
942 } else {
943 ZEND_UNREACHABLE();
944 }
945
946 zend_throw_exception_ex(zend_ce_compile_error, 0,
947 "Cannot use the %s modifier on a %s", zend_modifier_token_to_string(token), member);
948 return 0;
949 }
950
zend_modifier_list_to_flags(zend_modifier_target target,zend_ast * modifiers)951 uint32_t zend_modifier_list_to_flags(zend_modifier_target target, zend_ast *modifiers)
952 {
953 uint32_t flags = 0;
954 zend_ast_list *modifier_list = zend_ast_get_list(modifiers);
955
956 for (uint32_t i = 0; i < modifier_list->children; i++) {
957 uint32_t new_flag = zend_modifier_token_to_flag(target, (uint32_t) Z_LVAL_P(zend_ast_get_zval(modifier_list->child[i])));
958 if (!new_flag) {
959 return 0;
960 }
961 flags = zend_add_member_modifier(flags, new_flag, target);
962 if (!flags) {
963 return 0;
964 }
965 }
966
967 return flags;
968 }
969
zend_add_class_modifier(uint32_t flags,uint32_t new_flag)970 uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
971 {
972 uint32_t new_flags = flags | new_flag;
973 if ((flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
974 zend_throw_exception(zend_ce_compile_error,
975 "Multiple abstract modifiers are not allowed", 0);
976 return 0;
977 }
978 if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
979 zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
980 return 0;
981 }
982 if ((flags & ZEND_ACC_READONLY_CLASS) && (new_flag & ZEND_ACC_READONLY_CLASS)) {
983 zend_throw_exception(zend_ce_compile_error, "Multiple readonly modifiers are not allowed", 0);
984 return 0;
985 }
986 if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) {
987 zend_throw_exception(zend_ce_compile_error,
988 "Cannot use the final modifier on an abstract class", 0);
989 return 0;
990 }
991 return new_flags;
992 }
993 /* }}} */
994
zend_add_anonymous_class_modifier(uint32_t flags,uint32_t new_flag)995 uint32_t zend_add_anonymous_class_modifier(uint32_t flags, uint32_t new_flag)
996 {
997 uint32_t new_flags = flags | new_flag;
998 if (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
999 zend_throw_exception(zend_ce_compile_error,
1000 "Cannot use the abstract modifier on an anonymous class", 0);
1001 return 0;
1002 }
1003 if (new_flag & ZEND_ACC_FINAL) {
1004 zend_throw_exception(zend_ce_compile_error, "Cannot use the final modifier on an anonymous class", 0);
1005 return 0;
1006 }
1007 if ((flags & ZEND_ACC_READONLY_CLASS) && (new_flag & ZEND_ACC_READONLY_CLASS)) {
1008 zend_throw_exception(zend_ce_compile_error, "Multiple readonly modifiers are not allowed", 0);
1009 return 0;
1010 }
1011 return new_flags;
1012 }
1013
zend_add_member_modifier(uint32_t flags,uint32_t new_flag,zend_modifier_target target)1014 uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag, zend_modifier_target target) /* {{{ */
1015 {
1016 uint32_t new_flags = flags | new_flag;
1017 if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
1018 zend_throw_exception(zend_ce_compile_error,
1019 "Multiple access type modifiers are not allowed", 0);
1020 return 0;
1021 }
1022 if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) {
1023 zend_throw_exception(zend_ce_compile_error, "Multiple abstract modifiers are not allowed", 0);
1024 return 0;
1025 }
1026 if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) {
1027 zend_throw_exception(zend_ce_compile_error, "Multiple static modifiers are not allowed", 0);
1028 return 0;
1029 }
1030 if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
1031 zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
1032 return 0;
1033 }
1034 if ((flags & ZEND_ACC_READONLY) && (new_flag & ZEND_ACC_READONLY)) {
1035 zend_throw_exception(zend_ce_compile_error,
1036 "Multiple readonly modifiers are not allowed", 0);
1037 return 0;
1038 }
1039 if (target == ZEND_MODIFIER_TARGET_METHOD && (new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
1040 zend_throw_exception(zend_ce_compile_error,
1041 "Cannot use the final modifier on an abstract method", 0);
1042 return 0;
1043 }
1044 if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_CPP) {
1045 if ((flags & ZEND_ACC_PPP_SET_MASK) && (new_flag & ZEND_ACC_PPP_SET_MASK)) {
1046 zend_throw_exception(zend_ce_compile_error,
1047 "Multiple access type modifiers are not allowed", 0);
1048 return 0;
1049 }
1050 }
1051 return new_flags;
1052 }
1053 /* }}} */
1054
zend_create_member_string(zend_string * class_name,zend_string * member_name)1055 ZEND_API zend_string *zend_create_member_string(zend_string *class_name, zend_string *member_name) {
1056 return zend_string_concat3(
1057 ZSTR_VAL(class_name), ZSTR_LEN(class_name),
1058 "::", sizeof("::") - 1,
1059 ZSTR_VAL(member_name), ZSTR_LEN(member_name));
1060 }
1061
zend_concat_names(char * name1,size_t name1_len,char * name2,size_t name2_len)1062 static zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2, size_t name2_len) {
1063 return zend_string_concat3(name1, name1_len, "\\", 1, name2, name2_len);
1064 }
1065
zend_prefix_with_ns(zend_string * name)1066 static zend_string *zend_prefix_with_ns(zend_string *name) {
1067 if (FC(current_namespace)) {
1068 zend_string *ns = FC(current_namespace);
1069 return zend_concat_names(ZSTR_VAL(ns), ZSTR_LEN(ns), ZSTR_VAL(name), ZSTR_LEN(name));
1070 } else {
1071 return zend_string_copy(name);
1072 }
1073 }
1074
zend_resolve_non_class_name(zend_string * name,uint32_t type,bool * is_fully_qualified,bool case_sensitive,HashTable * current_import_sub)1075 static zend_string *zend_resolve_non_class_name(
1076 zend_string *name, uint32_t type, bool *is_fully_qualified,
1077 bool case_sensitive, HashTable *current_import_sub
1078 ) {
1079 char *compound;
1080 *is_fully_qualified = 0;
1081
1082 if (ZSTR_VAL(name)[0] == '\\') {
1083 /* Remove \ prefix (only relevant if this is a string rather than a label) */
1084 *is_fully_qualified = 1;
1085 return zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
1086 }
1087
1088 if (type == ZEND_NAME_FQ) {
1089 *is_fully_qualified = 1;
1090 return zend_string_copy(name);
1091 }
1092
1093 if (type == ZEND_NAME_RELATIVE) {
1094 *is_fully_qualified = 1;
1095 return zend_prefix_with_ns(name);
1096 }
1097
1098 if (current_import_sub) {
1099 /* If an unqualified name is a function/const alias, replace it. */
1100 zend_string *import_name;
1101 if (case_sensitive) {
1102 import_name = zend_hash_find_ptr(current_import_sub, name);
1103 } else {
1104 import_name = zend_hash_find_ptr_lc(current_import_sub, name);
1105 }
1106
1107 if (import_name) {
1108 *is_fully_qualified = 1;
1109 return zend_string_copy(import_name);
1110 }
1111 }
1112
1113 compound = memchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
1114 if (compound) {
1115 *is_fully_qualified = 1;
1116 }
1117
1118 if (compound && FC(imports)) {
1119 /* If the first part of a qualified name is an alias, substitute it. */
1120 size_t len = compound - ZSTR_VAL(name);
1121 zend_string *import_name = zend_hash_str_find_ptr_lc(FC(imports), ZSTR_VAL(name), len);
1122
1123 if (import_name) {
1124 return zend_concat_names(
1125 ZSTR_VAL(import_name), ZSTR_LEN(import_name), ZSTR_VAL(name) + len + 1, ZSTR_LEN(name) - len - 1);
1126 }
1127 }
1128
1129 return zend_prefix_with_ns(name);
1130 }
1131 /* }}} */
1132
zend_resolve_function_name(zend_string * name,uint32_t type,bool * is_fully_qualified)1133 static zend_string *zend_resolve_function_name(zend_string *name, uint32_t type, bool *is_fully_qualified)
1134 {
1135 return zend_resolve_non_class_name(
1136 name, type, is_fully_qualified, 0, FC(imports_function));
1137 }
1138
zend_resolve_const_name(zend_string * name,uint32_t type,bool * is_fully_qualified)1139 static zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bool *is_fully_qualified)
1140 {
1141 return zend_resolve_non_class_name(
1142 name, type, is_fully_qualified, 1, FC(imports_const));
1143 }
1144
zend_resolve_class_name(zend_string * name,uint32_t type)1145 static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /* {{{ */
1146 {
1147 char *compound;
1148
1149 if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
1150 if (type == ZEND_NAME_FQ) {
1151 zend_error_noreturn(E_COMPILE_ERROR,
1152 "'\\%s' is an invalid class name", ZSTR_VAL(name));
1153 }
1154 if (type == ZEND_NAME_RELATIVE) {
1155 zend_error_noreturn(E_COMPILE_ERROR,
1156 "'namespace\\%s' is an invalid class name", ZSTR_VAL(name));
1157 }
1158 ZEND_ASSERT(type == ZEND_NAME_NOT_FQ);
1159 return zend_string_copy(name);
1160 }
1161
1162 if (type == ZEND_NAME_RELATIVE) {
1163 return zend_prefix_with_ns(name);
1164 }
1165
1166 if (type == ZEND_NAME_FQ) {
1167 if (ZSTR_VAL(name)[0] == '\\') {
1168 /* Remove \ prefix (only relevant if this is a string rather than a label) */
1169 name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
1170 if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
1171 zend_error_noreturn(E_COMPILE_ERROR,
1172 "'\\%s' is an invalid class name", ZSTR_VAL(name));
1173 }
1174 return name;
1175 }
1176
1177 return zend_string_copy(name);
1178 }
1179
1180 if (FC(imports)) {
1181 compound = memchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
1182 if (compound) {
1183 /* If the first part of a qualified name is an alias, substitute it. */
1184 size_t len = compound - ZSTR_VAL(name);
1185 zend_string *import_name =
1186 zend_hash_str_find_ptr_lc(FC(imports), ZSTR_VAL(name), len);
1187
1188 if (import_name) {
1189 return zend_concat_names(
1190 ZSTR_VAL(import_name), ZSTR_LEN(import_name), ZSTR_VAL(name) + len + 1, ZSTR_LEN(name) - len - 1);
1191 }
1192 } else {
1193 /* If an unqualified name is an alias, replace it. */
1194 zend_string *import_name
1195 = zend_hash_find_ptr_lc(FC(imports), name);
1196
1197 if (import_name) {
1198 return zend_string_copy(import_name);
1199 }
1200 }
1201 }
1202
1203 /* If not fully qualified and not an alias, prepend the current namespace */
1204 return zend_prefix_with_ns(name);
1205 }
1206 /* }}} */
1207
zend_resolve_class_name_ast(zend_ast * ast)1208 static zend_string *zend_resolve_class_name_ast(zend_ast *ast) /* {{{ */
1209 {
1210 zval *class_name = zend_ast_get_zval(ast);
1211 if (Z_TYPE_P(class_name) != IS_STRING) {
1212 zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
1213 }
1214 return zend_resolve_class_name(Z_STR_P(class_name), ast->attr);
1215 }
1216 /* }}} */
1217
label_ptr_dtor(zval * zv)1218 static void label_ptr_dtor(zval *zv) /* {{{ */
1219 {
1220 efree_size(Z_PTR_P(zv), sizeof(zend_label));
1221 }
1222 /* }}} */
1223
str_dtor(zval * zv)1224 static void str_dtor(zval *zv) /* {{{ */ {
1225 zend_string_release_ex(Z_STR_P(zv), 0);
1226 }
1227 /* }}} */
1228
1229 static bool zend_is_call(zend_ast *ast);
1230
zend_add_try_element(uint32_t try_op)1231 static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
1232 {
1233 zend_op_array *op_array = CG(active_op_array);
1234 uint32_t try_catch_offset = op_array->last_try_catch++;
1235 zend_try_catch_element *elem;
1236
1237 op_array->try_catch_array = safe_erealloc(
1238 op_array->try_catch_array, sizeof(zend_try_catch_element), op_array->last_try_catch, 0);
1239
1240 elem = &op_array->try_catch_array[try_catch_offset];
1241 elem->try_op = try_op;
1242 elem->catch_op = 0;
1243 elem->finally_op = 0;
1244 elem->finally_end = 0;
1245
1246 return try_catch_offset;
1247 }
1248 /* }}} */
1249
function_add_ref(zend_function * function)1250 ZEND_API void function_add_ref(zend_function *function) /* {{{ */
1251 {
1252 if (function->type == ZEND_USER_FUNCTION) {
1253 zend_op_array *op_array = &function->op_array;
1254 if (op_array->refcount) {
1255 (*op_array->refcount)++;
1256 }
1257
1258 ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
1259 ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
1260 }
1261
1262 if (function->common.function_name) {
1263 zend_string_addref(function->common.function_name);
1264 }
1265 }
1266 /* }}} */
1267
do_bind_function_error(zend_string * lcname,zend_op_array * op_array,bool compile_time)1268 static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error(zend_string *lcname, zend_op_array *op_array, bool compile_time) /* {{{ */
1269 {
1270 zval *zv = zend_hash_find_known_hash(compile_time ? CG(function_table) : EG(function_table), lcname);
1271 int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
1272 zend_function *old_function;
1273
1274 ZEND_ASSERT(zv != NULL);
1275 old_function = (zend_function*)Z_PTR_P(zv);
1276 if (old_function->type == ZEND_USER_FUNCTION
1277 && old_function->op_array.last > 0) {
1278 zend_error_noreturn(error_level, "Cannot redeclare function %s() (previously declared in %s:%d)",
1279 op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name),
1280 ZSTR_VAL(old_function->op_array.filename),
1281 old_function->op_array.line_start);
1282 } else {
1283 zend_error_noreturn(error_level, "Cannot redeclare function %s()",
1284 op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name));
1285 }
1286 }
1287
do_bind_function(zend_function * func,zval * lcname)1288 ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname) /* {{{ */
1289 {
1290 zend_function *added_func = zend_hash_add_ptr(EG(function_table), Z_STR_P(lcname), func);
1291 if (UNEXPECTED(!added_func)) {
1292 do_bind_function_error(Z_STR_P(lcname), &func->op_array, 0);
1293 return FAILURE;
1294 }
1295
1296 if (func->op_array.refcount) {
1297 ++*func->op_array.refcount;
1298 }
1299 if (func->common.function_name) {
1300 zend_string_addref(func->common.function_name);
1301 }
1302 zend_observer_function_declared_notify(&func->op_array, Z_STR_P(lcname));
1303 return SUCCESS;
1304 }
1305 /* }}} */
1306
zend_bind_class_in_slot(zval * class_table_slot,zval * lcname,zend_string * lc_parent_name)1307 ZEND_API zend_class_entry *zend_bind_class_in_slot(
1308 zval *class_table_slot, zval *lcname, zend_string *lc_parent_name)
1309 {
1310 zend_class_entry *ce = Z_PTR_P(class_table_slot);
1311 bool is_preloaded =
1312 (ce->ce_flags & ZEND_ACC_PRELOADED) && !(CG(compiler_options) & ZEND_COMPILE_PRELOAD);
1313 bool success;
1314 if (EXPECTED(!is_preloaded)) {
1315 success = zend_hash_set_bucket_key(EG(class_table), (Bucket*) class_table_slot, Z_STR_P(lcname)) != NULL;
1316 } else {
1317 /* If preloading is used, don't replace the existing bucket, add a new one. */
1318 success = zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce) != NULL;
1319 }
1320 if (UNEXPECTED(!success)) {
1321 zend_class_entry *old_class = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
1322 ZEND_ASSERT(old_class);
1323 zend_class_redeclaration_error(E_COMPILE_ERROR, old_class);
1324 return NULL;
1325 }
1326
1327 if (ce->ce_flags & ZEND_ACC_LINKED) {
1328 zend_observer_class_linked_notify(ce, Z_STR_P(lcname));
1329 return ce;
1330 }
1331
1332 ce = zend_do_link_class(ce, lc_parent_name, Z_STR_P(lcname));
1333 if (ce) {
1334 ZEND_ASSERT(!EG(exception));
1335 zend_observer_class_linked_notify(ce, Z_STR_P(lcname));
1336 return ce;
1337 }
1338
1339 if (!is_preloaded) {
1340 /* Reload bucket pointer, the hash table may have been reallocated */
1341 zval *zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
1342 zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
1343 } else {
1344 zend_hash_del(EG(class_table), Z_STR_P(lcname));
1345 }
1346 return NULL;
1347 }
1348
do_bind_class(zval * lcname,zend_string * lc_parent_name)1349 ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name) /* {{{ */
1350 {
1351 zend_class_entry *ce;
1352 zval *rtd_key, *zv;
1353
1354 rtd_key = lcname + 1;
1355
1356 zv = zend_hash_find_known_hash(EG(class_table), Z_STR_P(rtd_key));
1357
1358 if (UNEXPECTED(!zv)) {
1359 ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
1360 ZEND_ASSERT(ce);
1361 zend_class_redeclaration_error(E_COMPILE_ERROR, ce);
1362 return FAILURE;
1363 }
1364
1365 /* Register the derived class */
1366 return zend_bind_class_in_slot(zv, lcname, lc_parent_name) ? SUCCESS : FAILURE;
1367 }
1368 /* }}} */
1369
add_type_string(zend_string * type,zend_string * new_type,bool is_intersection)1370 static zend_string *add_type_string(zend_string *type, zend_string *new_type, bool is_intersection) {
1371 zend_string *result;
1372 if (type == NULL) {
1373 return zend_string_copy(new_type);
1374 }
1375
1376 if (is_intersection) {
1377 result = zend_string_concat3(ZSTR_VAL(type), ZSTR_LEN(type),
1378 "&", 1, ZSTR_VAL(new_type), ZSTR_LEN(new_type));
1379 zend_string_release(type);
1380 } else {
1381 result = zend_string_concat3(
1382 ZSTR_VAL(type), ZSTR_LEN(type), "|", 1, ZSTR_VAL(new_type), ZSTR_LEN(new_type));
1383 zend_string_release(type);
1384 }
1385 return result;
1386 }
1387
resolve_class_name(zend_string * name,zend_class_entry * scope)1388 static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scope) {
1389 if (scope) {
1390 if (zend_string_equals_literal_ci(name, "self")) {
1391 name = scope->name;
1392 } else if (zend_string_equals_literal_ci(name, "parent") && scope->parent) {
1393 name = scope->parent->name;
1394 }
1395 }
1396
1397 /* The resolved name for anonymous classes contains null bytes. Cut off everything after the
1398 * null byte here, to avoid larger parts of the type being omitted by printing code later. */
1399 size_t len = strlen(ZSTR_VAL(name));
1400 if (len != ZSTR_LEN(name)) {
1401 ZEND_ASSERT(scope && "This should only happen with resolved types");
1402 return zend_string_init(ZSTR_VAL(name), len, 0);
1403 }
1404 return zend_string_copy(name);
1405 }
1406
add_intersection_type(zend_string * str,zend_type_list * intersection_type_list,zend_class_entry * scope,bool is_bracketed)1407 static zend_string *add_intersection_type(zend_string *str,
1408 zend_type_list *intersection_type_list, zend_class_entry *scope,
1409 bool is_bracketed)
1410 {
1411 zend_type *single_type;
1412 zend_string *intersection_str = NULL;
1413
1414 ZEND_TYPE_LIST_FOREACH(intersection_type_list, single_type) {
1415 ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*single_type));
1416 ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type));
1417 zend_string *name = ZEND_TYPE_NAME(*single_type);
1418 zend_string *resolved = resolve_class_name(name, scope);
1419 intersection_str = add_type_string(intersection_str, resolved, /* is_intersection */ true);
1420 zend_string_release(resolved);
1421 } ZEND_TYPE_LIST_FOREACH_END();
1422
1423 ZEND_ASSERT(intersection_str);
1424
1425 if (is_bracketed) {
1426 zend_string *result = zend_string_concat3("(", 1, ZSTR_VAL(intersection_str), ZSTR_LEN(intersection_str), ")", 1);
1427 zend_string_release(intersection_str);
1428 intersection_str = result;
1429 }
1430 str = add_type_string(str, intersection_str, /* is_intersection */ false);
1431 zend_string_release(intersection_str);
1432 return str;
1433 }
1434
zend_type_to_string_resolved(zend_type type,zend_class_entry * scope)1435 zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
1436 zend_string *str = NULL;
1437
1438 /* Pure intersection type */
1439 if (ZEND_TYPE_IS_INTERSECTION(type)) {
1440 ZEND_ASSERT(!ZEND_TYPE_IS_UNION(type));
1441 str = add_intersection_type(str, ZEND_TYPE_LIST(type), scope, /* is_bracketed */ false);
1442 } else if (ZEND_TYPE_HAS_LIST(type)) {
1443 /* A union type might not be a list */
1444 zend_type *list_type;
1445 ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
1446 if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
1447 str = add_intersection_type(str, ZEND_TYPE_LIST(*list_type), scope, /* is_bracketed */ true);
1448 continue;
1449 }
1450 ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
1451 ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
1452 zend_string *name = ZEND_TYPE_NAME(*list_type);
1453 zend_string *resolved = resolve_class_name(name, scope);
1454 str = add_type_string(str, resolved, /* is_intersection */ false);
1455 zend_string_release(resolved);
1456 } ZEND_TYPE_LIST_FOREACH_END();
1457 } else if (ZEND_TYPE_HAS_NAME(type)) {
1458 str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
1459 }
1460
1461 uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
1462
1463 if (type_mask == MAY_BE_ANY) {
1464 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_MIXED), /* is_intersection */ false);
1465
1466 return str;
1467 }
1468 if (type_mask & MAY_BE_STATIC) {
1469 zend_string *name = ZSTR_KNOWN(ZEND_STR_STATIC);
1470 // During compilation of eval'd code the called scope refers to the scope calling the eval
1471 if (scope && !zend_is_compiling()) {
1472 zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data));
1473 if (called_scope) {
1474 name = called_scope->name;
1475 }
1476 }
1477 str = add_type_string(str, name, /* is_intersection */ false);
1478 }
1479 if (type_mask & MAY_BE_CALLABLE) {
1480 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_CALLABLE), /* is_intersection */ false);
1481 }
1482 if (type_mask & MAY_BE_OBJECT) {
1483 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_OBJECT), /* is_intersection */ false);
1484 }
1485 if (type_mask & MAY_BE_ARRAY) {
1486 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_ARRAY), /* is_intersection */ false);
1487 }
1488 if (type_mask & MAY_BE_STRING) {
1489 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_STRING), /* is_intersection */ false);
1490 }
1491 if (type_mask & MAY_BE_LONG) {
1492 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_INT), /* is_intersection */ false);
1493 }
1494 if (type_mask & MAY_BE_DOUBLE) {
1495 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_FLOAT), /* is_intersection */ false);
1496 }
1497 if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
1498 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_BOOL), /* is_intersection */ false);
1499 } else if (type_mask & MAY_BE_FALSE) {
1500 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_FALSE), /* is_intersection */ false);
1501 } else if (type_mask & MAY_BE_TRUE) {
1502 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_TRUE), /* is_intersection */ false);
1503 }
1504 if (type_mask & MAY_BE_VOID) {
1505 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_VOID), /* is_intersection */ false);
1506 }
1507 if (type_mask & MAY_BE_NEVER) {
1508 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_NEVER), /* is_intersection */ false);
1509 }
1510
1511 if (type_mask & MAY_BE_NULL) {
1512 bool is_union = !str || memchr(ZSTR_VAL(str), '|', ZSTR_LEN(str)) != NULL;
1513 bool has_intersection = !str || memchr(ZSTR_VAL(str), '&', ZSTR_LEN(str)) != NULL;
1514 if (!is_union && !has_intersection) {
1515 zend_string *nullable_str = zend_string_concat2("?", 1, ZSTR_VAL(str), ZSTR_LEN(str));
1516 zend_string_release(str);
1517 return nullable_str;
1518 }
1519
1520 str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE), /* is_intersection */ false);
1521 }
1522 return str;
1523 }
1524
zend_type_to_string(zend_type type)1525 ZEND_API zend_string *zend_type_to_string(zend_type type) {
1526 return zend_type_to_string_resolved(type, NULL);
1527 }
1528
is_generator_compatible_class_type(zend_string * name)1529 static bool is_generator_compatible_class_type(zend_string *name) {
1530 return zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_TRAVERSABLE))
1531 || zend_string_equals_literal_ci(name, "Iterator")
1532 || zend_string_equals_literal_ci(name, "Generator");
1533 }
1534
zend_mark_function_as_generator(void)1535 static void zend_mark_function_as_generator(void) /* {{{ */
1536 {
1537 if (!CG(active_op_array)->function_name) {
1538 zend_error_noreturn(E_COMPILE_ERROR,
1539 "The \"yield\" expression can only be used inside a function");
1540 }
1541
1542 if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1543 zend_type return_type = CG(active_op_array)->arg_info[-1].type;
1544 bool valid_type = (ZEND_TYPE_FULL_MASK(return_type) & MAY_BE_OBJECT) != 0;
1545 if (!valid_type) {
1546 zend_type *single_type;
1547 ZEND_TYPE_FOREACH(return_type, single_type) {
1548 if (ZEND_TYPE_HAS_NAME(*single_type)
1549 && is_generator_compatible_class_type(ZEND_TYPE_NAME(*single_type))) {
1550 valid_type = 1;
1551 break;
1552 }
1553 } ZEND_TYPE_FOREACH_END();
1554 }
1555
1556 if (!valid_type) {
1557 zend_string *str = zend_type_to_string(return_type);
1558 zend_error_noreturn(E_COMPILE_ERROR,
1559 "Generator return type must be a supertype of Generator, %s given",
1560 ZSTR_VAL(str));
1561 }
1562 }
1563
1564 CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
1565 }
1566 /* }}} */
1567
zend_mangle_property_name(const char * src1,size_t src1_length,const char * src2,size_t src2_length,bool internal)1568 ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, bool internal) /* {{{ */
1569 {
1570 size_t prop_name_length = 1 + src1_length + 1 + src2_length;
1571 zend_string *prop_name = zend_string_alloc(prop_name_length, internal);
1572
1573 ZSTR_VAL(prop_name)[0] = '\0';
1574 memcpy(ZSTR_VAL(prop_name) + 1, src1, src1_length+1);
1575 memcpy(ZSTR_VAL(prop_name) + 1 + src1_length + 1, src2, src2_length+1);
1576 return prop_name;
1577 }
1578 /* }}} */
1579
zend_unmangle_property_name_ex(const zend_string * name,const char ** class_name,const char ** prop_name,size_t * prop_len)1580 ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len) /* {{{ */
1581 {
1582 size_t class_name_len;
1583 size_t anonclass_src_len;
1584
1585 *class_name = NULL;
1586
1587 if (!ZSTR_LEN(name) || ZSTR_VAL(name)[0] != '\0') {
1588 *prop_name = ZSTR_VAL(name);
1589 if (prop_len) {
1590 *prop_len = ZSTR_LEN(name);
1591 }
1592 return SUCCESS;
1593 }
1594 if (ZSTR_LEN(name) < 3 || ZSTR_VAL(name)[1] == '\0') {
1595 zend_error(E_NOTICE, "Illegal member variable name");
1596 *prop_name = ZSTR_VAL(name);
1597 if (prop_len) {
1598 *prop_len = ZSTR_LEN(name);
1599 }
1600 return FAILURE;
1601 }
1602
1603 class_name_len = zend_strnlen(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 2);
1604 if (class_name_len >= ZSTR_LEN(name) - 2 || ZSTR_VAL(name)[class_name_len + 1] != '\0') {
1605 zend_error(E_NOTICE, "Corrupt member variable name");
1606 *prop_name = ZSTR_VAL(name);
1607 if (prop_len) {
1608 *prop_len = ZSTR_LEN(name);
1609 }
1610 return FAILURE;
1611 }
1612
1613 *class_name = ZSTR_VAL(name) + 1;
1614 anonclass_src_len = zend_strnlen(*class_name + class_name_len + 1, ZSTR_LEN(name) - class_name_len - 2);
1615 if (class_name_len + anonclass_src_len + 2 != ZSTR_LEN(name)) {
1616 class_name_len += anonclass_src_len + 1;
1617 }
1618 *prop_name = ZSTR_VAL(name) + class_name_len + 2;
1619 if (prop_len) {
1620 *prop_len = ZSTR_LEN(name) - class_name_len - 2;
1621 }
1622 return SUCCESS;
1623 }
1624 /* }}} */
1625
array_is_const_ex(zend_array * array,uint32_t * max_checks)1626 static bool array_is_const_ex(zend_array *array, uint32_t *max_checks)
1627 {
1628 if (zend_hash_num_elements(array) > *max_checks) {
1629 return false;
1630 }
1631 *max_checks -= zend_hash_num_elements(array);
1632
1633 zval *element;
1634 ZEND_HASH_FOREACH_VAL(array, element) {
1635 if (Z_TYPE_P(element) < IS_ARRAY) {
1636 continue;
1637 } else if (Z_TYPE_P(element) == IS_ARRAY) {
1638 if (!array_is_const_ex(array, max_checks)) {
1639 return false;
1640 }
1641 } else {
1642 return false;
1643 }
1644 } ZEND_HASH_FOREACH_END();
1645
1646 return true;
1647 }
1648
array_is_const(zend_array * array)1649 static bool array_is_const(zend_array *array)
1650 {
1651 uint32_t max_checks = 50;
1652 return array_is_const_ex(array, &max_checks);
1653 }
1654
can_ct_eval_const(zend_constant * c)1655 static bool can_ct_eval_const(zend_constant *c) {
1656 if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) {
1657 return 0;
1658 }
1659 if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)
1660 && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION)
1661 && !((ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE)
1662 && (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
1663 return 1;
1664 }
1665 if (Z_TYPE(c->value) < IS_ARRAY
1666 && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
1667 return 1;
1668 } else if (Z_TYPE(c->value) == IS_ARRAY
1669 && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)
1670 && array_is_const(Z_ARR(c->value))) {
1671 return 1;
1672 }
1673 return 0;
1674 }
1675
zend_try_ct_eval_const(zval * zv,zend_string * name,bool is_fully_qualified)1676 static bool zend_try_ct_eval_const(zval *zv, zend_string *name, bool is_fully_qualified) /* {{{ */
1677 {
1678 /* Substitute true, false and null (including unqualified usage in namespaces)
1679 * before looking up the possibly namespaced name. */
1680 const char *lookup_name = ZSTR_VAL(name);
1681 size_t lookup_len = ZSTR_LEN(name);
1682
1683 if (!is_fully_qualified) {
1684 zend_get_unqualified_name(name, &lookup_name, &lookup_len);
1685 }
1686
1687 zend_constant *c;
1688 if ((c = zend_get_special_const(lookup_name, lookup_len))) {
1689 ZVAL_COPY_VALUE(zv, &c->value);
1690 return 1;
1691 }
1692 c = zend_hash_find_ptr(EG(zend_constants), name);
1693 if (c && can_ct_eval_const(c)) {
1694 ZVAL_COPY_OR_DUP(zv, &c->value);
1695 return 1;
1696 }
1697 return 0;
1698 }
1699 /* }}} */
1700
zend_is_scope_known(void)1701 static inline bool zend_is_scope_known(void) /* {{{ */
1702 {
1703 if (!CG(active_op_array)) {
1704 /* This can only happen when evaluating a default value string. */
1705 return 0;
1706 }
1707
1708 if (CG(active_op_array)->fn_flags & ZEND_ACC_CLOSURE) {
1709 /* Closures can be rebound to a different scope */
1710 return 0;
1711 }
1712
1713 if (!CG(active_class_entry)) {
1714 /* The scope is known if we're in a free function (no scope), but not if we're in
1715 * a file/eval (which inherits including/eval'ing scope). */
1716 return CG(active_op_array)->function_name != NULL;
1717 }
1718
1719 /* For traits self etc refers to the using class, not the trait itself */
1720 return (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) == 0;
1721 }
1722 /* }}} */
1723
class_name_refers_to_active_ce(zend_string * class_name,uint32_t fetch_type)1724 static inline bool class_name_refers_to_active_ce(zend_string *class_name, uint32_t fetch_type) /* {{{ */
1725 {
1726 if (!CG(active_class_entry)) {
1727 return 0;
1728 }
1729 if (fetch_type == ZEND_FETCH_CLASS_SELF && zend_is_scope_known()) {
1730 return 1;
1731 }
1732 return fetch_type == ZEND_FETCH_CLASS_DEFAULT
1733 && zend_string_equals_ci(class_name, CG(active_class_entry)->name);
1734 }
1735 /* }}} */
1736
zend_get_class_fetch_type(const zend_string * name)1737 uint32_t zend_get_class_fetch_type(const zend_string *name) /* {{{ */
1738 {
1739 if (zend_string_equals_literal_ci(name, "self")) {
1740 return ZEND_FETCH_CLASS_SELF;
1741 } else if (zend_string_equals_literal_ci(name, "parent")) {
1742 return ZEND_FETCH_CLASS_PARENT;
1743 } else if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_STATIC))) {
1744 return ZEND_FETCH_CLASS_STATIC;
1745 } else {
1746 return ZEND_FETCH_CLASS_DEFAULT;
1747 }
1748 }
1749 /* }}} */
1750
zend_get_class_fetch_type_ast(zend_ast * name_ast)1751 static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
1752 {
1753 /* Fully qualified names are always default refs */
1754 if (name_ast->attr == ZEND_NAME_FQ) {
1755 return ZEND_FETCH_CLASS_DEFAULT;
1756 }
1757
1758 return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
1759 }
1760 /* }}} */
1761
zend_resolve_const_class_name_reference(zend_ast * ast,const char * type)1762 static zend_string *zend_resolve_const_class_name_reference(zend_ast *ast, const char *type)
1763 {
1764 zend_string *class_name = zend_ast_get_str(ast);
1765 if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type_ast(ast)) {
1766 zend_error_noreturn(E_COMPILE_ERROR,
1767 "Cannot use \"%s\" as %s, as it is reserved",
1768 ZSTR_VAL(class_name), type);
1769 }
1770 return zend_resolve_class_name(class_name, ast->attr);
1771 }
1772
zend_ensure_valid_class_fetch_type(uint32_t fetch_type)1773 static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
1774 {
1775 if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && zend_is_scope_known()) {
1776 zend_class_entry *ce = CG(active_class_entry);
1777 if (!ce) {
1778 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
1779 fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
1780 fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
1781 } else if (fetch_type == ZEND_FETCH_CLASS_PARENT && !ce->parent_name) {
1782 zend_error_noreturn(E_COMPILE_ERROR,
1783 "Cannot use \"parent\" when current class scope has no parent");
1784 }
1785 }
1786 }
1787 /* }}} */
1788
zend_try_compile_const_expr_resolve_class_name(zval * zv,zend_ast * class_ast)1789 static bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast) /* {{{ */
1790 {
1791 uint32_t fetch_type;
1792 zval *class_name;
1793
1794 if (class_ast->kind != ZEND_AST_ZVAL) {
1795 return 0;
1796 }
1797
1798 class_name = zend_ast_get_zval(class_ast);
1799
1800 if (Z_TYPE_P(class_name) != IS_STRING) {
1801 zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
1802 }
1803
1804 fetch_type = zend_get_class_fetch_type(Z_STR_P(class_name));
1805 zend_ensure_valid_class_fetch_type(fetch_type);
1806
1807 switch (fetch_type) {
1808 case ZEND_FETCH_CLASS_SELF:
1809 if (CG(active_class_entry) && zend_is_scope_known()) {
1810 ZVAL_STR_COPY(zv, CG(active_class_entry)->name);
1811 return 1;
1812 }
1813 return 0;
1814 case ZEND_FETCH_CLASS_PARENT:
1815 if (CG(active_class_entry) && CG(active_class_entry)->parent_name
1816 && zend_is_scope_known()) {
1817 ZVAL_STR_COPY(zv, CG(active_class_entry)->parent_name);
1818 return 1;
1819 }
1820 return 0;
1821 case ZEND_FETCH_CLASS_STATIC:
1822 return 0;
1823 case ZEND_FETCH_CLASS_DEFAULT:
1824 ZVAL_STR(zv, zend_resolve_class_name_ast(class_ast));
1825 return 1;
1826 EMPTY_SWITCH_DEFAULT_CASE()
1827 }
1828 }
1829 /* }}} */
1830
1831 /* We don't use zend_verify_const_access because we need to deal with unlinked classes. */
zend_verify_ct_const_access(zend_class_constant * c,zend_class_entry * scope)1832 static bool zend_verify_ct_const_access(zend_class_constant *c, zend_class_entry *scope)
1833 {
1834 if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED) {
1835 return 0;
1836 } else if (c->ce->ce_flags & ZEND_ACC_TRAIT) {
1837 /* This condition is only met on directly accessing trait constants,
1838 * because the ce is replaced to the class entry of the composing class
1839 * on binding. */
1840 return 0;
1841 } else if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PUBLIC) {
1842 return 1;
1843 } else if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PRIVATE) {
1844 return c->ce == scope;
1845 } else {
1846 zend_class_entry *ce = c->ce;
1847 while (1) {
1848 if (ce == scope) {
1849 return 1;
1850 }
1851 if (!ce->parent) {
1852 break;
1853 }
1854 if (ce->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
1855 ce = ce->parent;
1856 } else {
1857 ce = zend_hash_find_ptr_lc(CG(class_table), ce->parent_name);
1858 if (!ce) {
1859 break;
1860 }
1861 }
1862 }
1863 /* Reverse case cannot be true during compilation */
1864 return 0;
1865 }
1866 }
1867
zend_try_ct_eval_class_const(zval * zv,zend_string * class_name,zend_string * name)1868 static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
1869 {
1870 uint32_t fetch_type = zend_get_class_fetch_type(class_name);
1871 zend_class_constant *cc;
1872 zval *c;
1873
1874 if (class_name_refers_to_active_ce(class_name, fetch_type)) {
1875 cc = zend_hash_find_ptr(&CG(active_class_entry)->constants_table, name);
1876 } else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
1877 zend_class_entry *ce = zend_hash_find_ptr_lc(CG(class_table), class_name);
1878 if (ce) {
1879 cc = zend_hash_find_ptr(&ce->constants_table, name);
1880 } else {
1881 return 0;
1882 }
1883 } else {
1884 return 0;
1885 }
1886
1887 if (CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) {
1888 return 0;
1889 }
1890
1891 if (!cc || !zend_verify_ct_const_access(cc, CG(active_class_entry))) {
1892 return 0;
1893 }
1894
1895 c = &cc->value;
1896
1897 /* Substitute case-sensitive (or lowercase) persistent class constants */
1898 if (Z_TYPE_P(c) < IS_ARRAY) {
1899 ZVAL_COPY_OR_DUP(zv, c);
1900 return 1;
1901 } else if (Z_TYPE_P(c) == IS_ARRAY && array_is_const(Z_ARR_P(c))) {
1902 ZVAL_COPY_OR_DUP(zv, c);
1903 return 1;
1904 }
1905
1906 return 0;
1907 }
1908 /* }}} */
1909
zend_add_to_list(void * result,void * item)1910 static void zend_add_to_list(void *result, void *item) /* {{{ */
1911 {
1912 void** list = *(void**)result;
1913 size_t n = 0;
1914
1915 if (list) {
1916 while (list[n]) {
1917 n++;
1918 }
1919 }
1920
1921 list = erealloc(list, sizeof(void*) * (n+2));
1922
1923 list[n] = item;
1924 list[n+1] = NULL;
1925
1926 *(void**)result = list;
1927 }
1928 /* }}} */
1929
zend_do_extended_stmt(void)1930 static void zend_do_extended_stmt(void) /* {{{ */
1931 {
1932 zend_op *opline;
1933
1934 if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT)) {
1935 return;
1936 }
1937
1938 opline = get_next_op();
1939
1940 opline->opcode = ZEND_EXT_STMT;
1941 }
1942 /* }}} */
1943
zend_do_extended_fcall_begin(void)1944 static void zend_do_extended_fcall_begin(void) /* {{{ */
1945 {
1946 zend_op *opline;
1947
1948 if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_FCALL)) {
1949 return;
1950 }
1951
1952 opline = get_next_op();
1953
1954 opline->opcode = ZEND_EXT_FCALL_BEGIN;
1955 }
1956 /* }}} */
1957
zend_do_extended_fcall_end(void)1958 static void zend_do_extended_fcall_end(void) /* {{{ */
1959 {
1960 zend_op *opline;
1961
1962 if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_FCALL)) {
1963 return;
1964 }
1965
1966 opline = get_next_op();
1967
1968 opline->opcode = ZEND_EXT_FCALL_END;
1969 }
1970 /* }}} */
1971
zend_is_auto_global_str(const char * name,size_t len)1972 ZEND_API bool zend_is_auto_global_str(const char *name, size_t len) /* {{{ */ {
1973 zend_auto_global *auto_global;
1974
1975 if ((auto_global = zend_hash_str_find_ptr(CG(auto_globals), name, len)) != NULL) {
1976 if (auto_global->armed) {
1977 auto_global->armed = auto_global->auto_global_callback(auto_global->name);
1978 }
1979 return 1;
1980 }
1981 return 0;
1982 }
1983 /* }}} */
1984
zend_is_auto_global(zend_string * name)1985 ZEND_API bool zend_is_auto_global(zend_string *name) /* {{{ */
1986 {
1987 zend_auto_global *auto_global;
1988
1989 if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
1990 if (auto_global->armed) {
1991 auto_global->armed = auto_global->auto_global_callback(auto_global->name);
1992 }
1993 return 1;
1994 }
1995 return 0;
1996 }
1997 /* }}} */
1998
zend_register_auto_global(zend_string * name,bool jit,zend_auto_global_callback auto_global_callback)1999 ZEND_API zend_result zend_register_auto_global(zend_string *name, bool jit, zend_auto_global_callback auto_global_callback) /* {{{ */
2000 {
2001 zend_auto_global auto_global;
2002 zend_result retval;
2003
2004 auto_global.name = name;
2005 auto_global.auto_global_callback = auto_global_callback;
2006 auto_global.jit = jit;
2007
2008 retval = zend_hash_add_mem(CG(auto_globals), auto_global.name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE;
2009
2010 return retval;
2011 }
2012 /* }}} */
2013
zend_activate_auto_globals(void)2014 ZEND_API void zend_activate_auto_globals(void) /* {{{ */
2015 {
2016 zend_auto_global *auto_global;
2017
2018 ZEND_HASH_MAP_FOREACH_PTR(CG(auto_globals), auto_global) {
2019 if (auto_global->jit) {
2020 auto_global->armed = 1;
2021 } else if (auto_global->auto_global_callback) {
2022 auto_global->armed = auto_global->auto_global_callback(auto_global->name);
2023 } else {
2024 auto_global->armed = 0;
2025 }
2026 } ZEND_HASH_FOREACH_END();
2027 }
2028 /* }}} */
2029
zendlex(zend_parser_stack_elem * elem)2030 int ZEND_FASTCALL zendlex(zend_parser_stack_elem *elem) /* {{{ */
2031 {
2032 zval zv;
2033 int ret;
2034
2035 if (CG(increment_lineno)) {
2036 CG(zend_lineno)++;
2037 CG(increment_lineno) = 0;
2038 }
2039
2040 ret = lex_scan(&zv, elem);
2041 ZEND_ASSERT(!EG(exception) || ret == T_ERROR);
2042 return ret;
2043
2044 }
2045 /* }}} */
2046
zend_initialize_class_data(zend_class_entry * ce,bool nullify_handlers)2047 ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_handlers) /* {{{ */
2048 {
2049 bool persistent_hashes = ce->type == ZEND_INTERNAL_CLASS;
2050
2051 ce->refcount = 1;
2052 ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED;
2053
2054 if (CG(compiler_options) & ZEND_COMPILE_GUARDS) {
2055 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2056 }
2057
2058 ce->default_properties_table = NULL;
2059 ce->default_static_members_table = NULL;
2060 zend_hash_init(&ce->properties_info, 8, NULL, NULL, persistent_hashes);
2061 zend_hash_init(&ce->constants_table, 8, NULL, NULL, persistent_hashes);
2062 zend_hash_init(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes);
2063
2064 ce->doc_comment = NULL;
2065
2066 ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
2067 ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
2068
2069 ce->default_object_handlers = &std_object_handlers;
2070 ce->default_properties_count = 0;
2071 ce->default_static_members_count = 0;
2072 ce->properties_info_table = NULL;
2073 ce->attributes = NULL;
2074 ce->enum_backing_type = IS_UNDEF;
2075 ce->backed_enum_table = NULL;
2076
2077 if (nullify_handlers) {
2078 ce->constructor = NULL;
2079 ce->destructor = NULL;
2080 ce->clone = NULL;
2081 ce->__get = NULL;
2082 ce->__set = NULL;
2083 ce->__unset = NULL;
2084 ce->__isset = NULL;
2085 ce->__call = NULL;
2086 ce->__callstatic = NULL;
2087 ce->__tostring = NULL;
2088 ce->__serialize = NULL;
2089 ce->__unserialize = NULL;
2090 ce->__debugInfo = NULL;
2091 ce->create_object = NULL;
2092 ce->get_iterator = NULL;
2093 ce->iterator_funcs_ptr = NULL;
2094 ce->arrayaccess_funcs_ptr = NULL;
2095 ce->get_static_method = NULL;
2096 ce->parent = NULL;
2097 ce->parent_name = NULL;
2098 ce->num_interfaces = 0;
2099 ce->interfaces = NULL;
2100 ce->num_traits = 0;
2101 ce->num_hooked_props = 0;
2102 ce->num_hooked_prop_variance_checks = 0;
2103 ce->trait_names = NULL;
2104 ce->trait_aliases = NULL;
2105 ce->trait_precedences = NULL;
2106 ce->serialize = NULL;
2107 ce->unserialize = NULL;
2108 if (ce->type == ZEND_INTERNAL_CLASS) {
2109 ce->info.internal.module = NULL;
2110 ce->info.internal.builtin_functions = NULL;
2111 }
2112 }
2113 }
2114 /* }}} */
2115
zend_get_compiled_variable_name(const zend_op_array * op_array,uint32_t var)2116 ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var) /* {{{ */
2117 {
2118 return op_array->vars[EX_VAR_TO_NUM(var)];
2119 }
2120 /* }}} */
2121
zend_ast_append_str(zend_ast * left_ast,zend_ast * right_ast)2122 zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */
2123 {
2124 zval *left_zv = zend_ast_get_zval(left_ast);
2125 zend_string *left = Z_STR_P(left_zv);
2126 zend_string *right = zend_ast_get_str(right_ast);
2127
2128 zend_string *result;
2129 size_t left_len = ZSTR_LEN(left);
2130 size_t len = left_len + ZSTR_LEN(right) + 1; /* left\right */
2131
2132 result = zend_string_extend(left, len, 0);
2133 ZSTR_VAL(result)[left_len] = '\\';
2134 memcpy(&ZSTR_VAL(result)[left_len + 1], ZSTR_VAL(right), ZSTR_LEN(right));
2135 ZSTR_VAL(result)[len] = '\0';
2136 zend_string_release_ex(right, 0);
2137
2138 ZVAL_STR(left_zv, result);
2139 return left_ast;
2140 }
2141 /* }}} */
2142
zend_negate_num_string(zend_ast * ast)2143 zend_ast *zend_negate_num_string(zend_ast *ast) /* {{{ */
2144 {
2145 zval *zv = zend_ast_get_zval(ast);
2146 if (Z_TYPE_P(zv) == IS_LONG) {
2147 if (Z_LVAL_P(zv) == 0) {
2148 ZVAL_NEW_STR(zv, ZSTR_INIT_LITERAL("-0", 0));
2149 } else {
2150 ZEND_ASSERT(Z_LVAL_P(zv) > 0);
2151 Z_LVAL_P(zv) *= -1;
2152 }
2153 } else if (Z_TYPE_P(zv) == IS_STRING) {
2154 size_t orig_len = Z_STRLEN_P(zv);
2155 Z_STR_P(zv) = zend_string_extend(Z_STR_P(zv), orig_len + 1, 0);
2156 memmove(Z_STRVAL_P(zv) + 1, Z_STRVAL_P(zv), orig_len + 1);
2157 Z_STRVAL_P(zv)[0] = '-';
2158 } else {
2159 ZEND_UNREACHABLE();
2160 }
2161 return ast;
2162 }
2163 /* }}} */
2164
zend_verify_namespace(void)2165 static void zend_verify_namespace(void) /* {{{ */
2166 {
2167 if (FC(has_bracketed_namespaces) && !FC(in_namespace)) {
2168 zend_error_noreturn(E_COMPILE_ERROR, "No code may exist outside of namespace {}");
2169 }
2170 }
2171 /* }}} */
2172
2173 /* {{{ zend_dirname
2174 Returns directory name component of path */
zend_dirname(char * path,size_t len)2175 ZEND_API size_t zend_dirname(char *path, size_t len)
2176 {
2177 char *end = path + len - 1;
2178 unsigned int len_adjust = 0;
2179
2180 #ifdef ZEND_WIN32
2181 /* Note that on Win32 CWD is per drive (heritage from CP/M).
2182 * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
2183 */
2184 if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
2185 /* Skip over the drive spec (if any) so as not to change */
2186 path += 2;
2187 len_adjust += 2;
2188 if (2 == len) {
2189 /* Return "c:" on Win32 for dirname("c:").
2190 * It would be more consistent to return "c:."
2191 * but that would require making the string *longer*.
2192 */
2193 return len;
2194 }
2195 }
2196 #endif
2197
2198 if (len == 0) {
2199 /* Illegal use of this function */
2200 return 0;
2201 }
2202
2203 /* Strip trailing slashes */
2204 while (end >= path && IS_SLASH_P(end)) {
2205 end--;
2206 }
2207 if (end < path) {
2208 /* The path only contained slashes */
2209 path[0] = DEFAULT_SLASH;
2210 path[1] = '\0';
2211 return 1 + len_adjust;
2212 }
2213
2214 /* Strip filename */
2215 while (end >= path && !IS_SLASH_P(end)) {
2216 end--;
2217 }
2218 if (end < path) {
2219 /* No slash found, therefore return '.' */
2220 path[0] = '.';
2221 path[1] = '\0';
2222 return 1 + len_adjust;
2223 }
2224
2225 /* Strip slashes which came before the file name */
2226 while (end >= path && IS_SLASH_P(end)) {
2227 end--;
2228 }
2229 if (end < path) {
2230 path[0] = DEFAULT_SLASH;
2231 path[1] = '\0';
2232 return 1 + len_adjust;
2233 }
2234 *(end+1) = '\0';
2235
2236 return (size_t)(end + 1 - path) + len_adjust;
2237 }
2238 /* }}} */
2239
zend_adjust_for_fetch_type(zend_op * opline,znode * result,uint32_t type)2240 static void zend_adjust_for_fetch_type(zend_op *opline, znode *result, uint32_t type) /* {{{ */
2241 {
2242 uint_fast8_t factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3;
2243
2244 switch (type) {
2245 case BP_VAR_R:
2246 opline->result_type = IS_TMP_VAR;
2247 result->op_type = IS_TMP_VAR;
2248 return;
2249 case BP_VAR_W:
2250 opline->opcode += 1 * factor;
2251 return;
2252 case BP_VAR_RW:
2253 opline->opcode += 2 * factor;
2254 return;
2255 case BP_VAR_IS:
2256 opline->result_type = IS_TMP_VAR;
2257 result->op_type = IS_TMP_VAR;
2258 opline->opcode += 3 * factor;
2259 return;
2260 case BP_VAR_FUNC_ARG:
2261 opline->opcode += 4 * factor;
2262 return;
2263 case BP_VAR_UNSET:
2264 opline->opcode += 5 * factor;
2265 return;
2266 EMPTY_SWITCH_DEFAULT_CASE()
2267 }
2268 }
2269 /* }}} */
2270
zend_make_var_result(znode * result,zend_op * opline)2271 static inline void zend_make_var_result(znode *result, zend_op *opline) /* {{{ */
2272 {
2273 opline->result_type = IS_VAR;
2274 opline->result.var = get_temporary_variable();
2275 GET_NODE(result, opline->result);
2276 }
2277 /* }}} */
2278
zend_make_tmp_result(znode * result,zend_op * opline)2279 static inline void zend_make_tmp_result(znode *result, zend_op *opline) /* {{{ */
2280 {
2281 opline->result_type = IS_TMP_VAR;
2282 opline->result.var = get_temporary_variable();
2283 GET_NODE(result, opline->result);
2284 }
2285 /* }}} */
2286
zend_emit_op(znode * result,uint8_t opcode,znode * op1,znode * op2)2287 static zend_op *zend_emit_op(znode *result, uint8_t opcode, znode *op1, znode *op2) /* {{{ */
2288 {
2289 zend_op *opline = get_next_op();
2290 opline->opcode = opcode;
2291
2292 if (op1 != NULL) {
2293 SET_NODE(opline->op1, op1);
2294 }
2295
2296 if (op2 != NULL) {
2297 SET_NODE(opline->op2, op2);
2298 }
2299
2300 if (result) {
2301 zend_make_var_result(result, opline);
2302 }
2303 return opline;
2304 }
2305 /* }}} */
2306
zend_emit_op_tmp(znode * result,uint8_t opcode,znode * op1,znode * op2)2307 static zend_op *zend_emit_op_tmp(znode *result, uint8_t opcode, znode *op1, znode *op2) /* {{{ */
2308 {
2309 zend_op *opline = get_next_op();
2310 opline->opcode = opcode;
2311
2312 if (op1 != NULL) {
2313 SET_NODE(opline->op1, op1);
2314 }
2315
2316 if (op2 != NULL) {
2317 SET_NODE(opline->op2, op2);
2318 }
2319
2320 if (result) {
2321 zend_make_tmp_result(result, opline);
2322 }
2323
2324 return opline;
2325 }
2326 /* }}} */
2327
zend_emit_tick(void)2328 static void zend_emit_tick(void) /* {{{ */
2329 {
2330 zend_op *opline;
2331
2332 /* This prevents a double TICK generated by the parser statement of "declare()" */
2333 if (CG(active_op_array)->last && CG(active_op_array)->opcodes[CG(active_op_array)->last - 1].opcode == ZEND_TICKS) {
2334 return;
2335 }
2336
2337 opline = get_next_op();
2338
2339 opline->opcode = ZEND_TICKS;
2340 opline->extended_value = FC(declarables).ticks;
2341 }
2342 /* }}} */
2343
zend_emit_op_data(znode * value)2344 static inline zend_op *zend_emit_op_data(znode *value) /* {{{ */
2345 {
2346 return zend_emit_op(NULL, ZEND_OP_DATA, value, NULL);
2347 }
2348 /* }}} */
2349
zend_emit_jump(uint32_t opnum_target)2350 static inline uint32_t zend_emit_jump(uint32_t opnum_target) /* {{{ */
2351 {
2352 uint32_t opnum = get_next_op_number();
2353 zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL);
2354 opline->op1.opline_num = opnum_target;
2355 return opnum;
2356 }
2357 /* }}} */
2358
zend_is_smart_branch(const zend_op * opline)2359 ZEND_API bool zend_is_smart_branch(const zend_op *opline) /* {{{ */
2360 {
2361 switch (opline->opcode) {
2362 case ZEND_IS_IDENTICAL:
2363 case ZEND_IS_NOT_IDENTICAL:
2364 case ZEND_IS_EQUAL:
2365 case ZEND_IS_NOT_EQUAL:
2366 case ZEND_IS_SMALLER:
2367 case ZEND_IS_SMALLER_OR_EQUAL:
2368 case ZEND_CASE:
2369 case ZEND_CASE_STRICT:
2370 case ZEND_ISSET_ISEMPTY_CV:
2371 case ZEND_ISSET_ISEMPTY_VAR:
2372 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
2373 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
2374 case ZEND_ISSET_ISEMPTY_STATIC_PROP:
2375 case ZEND_INSTANCEOF:
2376 case ZEND_TYPE_CHECK:
2377 case ZEND_DEFINED:
2378 case ZEND_IN_ARRAY:
2379 case ZEND_ARRAY_KEY_EXISTS:
2380 return 1;
2381 default:
2382 return 0;
2383 }
2384 }
2385 /* }}} */
2386
zend_emit_cond_jump(uint8_t opcode,znode * cond,uint32_t opnum_target)2387 static inline uint32_t zend_emit_cond_jump(uint8_t opcode, znode *cond, uint32_t opnum_target) /* {{{ */
2388 {
2389 uint32_t opnum = get_next_op_number();
2390 zend_op *opline;
2391
2392 if (cond->op_type == IS_TMP_VAR && opnum > 0) {
2393 opline = CG(active_op_array)->opcodes + opnum - 1;
2394 if (opline->result_type == IS_TMP_VAR
2395 && opline->result.var == cond->u.op.var
2396 && zend_is_smart_branch(opline)) {
2397 if (opcode == ZEND_JMPZ) {
2398 opline->result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPZ;
2399 } else {
2400 ZEND_ASSERT(opcode == ZEND_JMPNZ);
2401 opline->result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPNZ;
2402 }
2403 }
2404 }
2405 opline = zend_emit_op(NULL, opcode, cond, NULL);
2406 opline->op2.opline_num = opnum_target;
2407 return opnum;
2408 }
2409 /* }}} */
2410
zend_update_jump_target(uint32_t opnum_jump,uint32_t opnum_target)2411 static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_target) /* {{{ */
2412 {
2413 zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump];
2414 switch (opline->opcode) {
2415 case ZEND_JMP:
2416 opline->op1.opline_num = opnum_target;
2417 break;
2418 case ZEND_JMPZ:
2419 case ZEND_JMPNZ:
2420 case ZEND_JMPZ_EX:
2421 case ZEND_JMPNZ_EX:
2422 case ZEND_JMP_SET:
2423 case ZEND_COALESCE:
2424 case ZEND_JMP_NULL:
2425 case ZEND_BIND_INIT_STATIC_OR_JMP:
2426 case ZEND_JMP_FRAMELESS:
2427 opline->op2.opline_num = opnum_target;
2428 break;
2429 EMPTY_SWITCH_DEFAULT_CASE()
2430 }
2431 }
2432 /* }}} */
2433
zend_update_jump_target_to_next(uint32_t opnum_jump)2434 static inline void zend_update_jump_target_to_next(uint32_t opnum_jump) /* {{{ */
2435 {
2436 zend_update_jump_target(opnum_jump, get_next_op_number());
2437 }
2438 /* }}} */
2439
zend_delayed_emit_op(znode * result,uint8_t opcode,znode * op1,znode * op2)2440 static inline zend_op *zend_delayed_emit_op(znode *result, uint8_t opcode, znode *op1, znode *op2) /* {{{ */
2441 {
2442 zend_op tmp_opline;
2443
2444 init_op(&tmp_opline);
2445
2446 tmp_opline.opcode = opcode;
2447 if (op1 != NULL) {
2448 SET_NODE(tmp_opline.op1, op1);
2449 }
2450 if (op2 != NULL) {
2451 SET_NODE(tmp_opline.op2, op2);
2452 }
2453 if (result) {
2454 zend_make_var_result(result, &tmp_opline);
2455 }
2456
2457 zend_stack_push(&CG(delayed_oplines_stack), &tmp_opline);
2458 return zend_stack_top(&CG(delayed_oplines_stack));
2459 }
2460 /* }}} */
2461
zend_delayed_compile_begin(void)2462 static inline uint32_t zend_delayed_compile_begin(void) /* {{{ */
2463 {
2464 return zend_stack_count(&CG(delayed_oplines_stack));
2465 }
2466 /* }}} */
2467
zend_delayed_compile_end(uint32_t offset)2468 static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
2469 {
2470 zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
2471 uint32_t i, count = zend_stack_count(&CG(delayed_oplines_stack));
2472
2473 ZEND_ASSERT(count >= offset);
2474 for (i = offset; i < count; ++i) {
2475 if (EXPECTED(oplines[i].opcode != ZEND_NOP)) {
2476 opline = get_next_op();
2477 memcpy(opline, &oplines[i], sizeof(zend_op));
2478 } else {
2479 opline = CG(active_op_array)->opcodes + oplines[i].extended_value;
2480 }
2481 }
2482
2483 CG(delayed_oplines_stack).top = offset;
2484 return opline;
2485 }
2486 /* }}} */
2487
zend_ast_kind_is_short_circuited(zend_ast_kind ast_kind)2488 static bool zend_ast_kind_is_short_circuited(zend_ast_kind ast_kind)
2489 {
2490 switch (ast_kind) {
2491 case ZEND_AST_DIM:
2492 case ZEND_AST_PROP:
2493 case ZEND_AST_NULLSAFE_PROP:
2494 case ZEND_AST_STATIC_PROP:
2495 case ZEND_AST_METHOD_CALL:
2496 case ZEND_AST_NULLSAFE_METHOD_CALL:
2497 case ZEND_AST_STATIC_CALL:
2498 return 1;
2499 default:
2500 return 0;
2501 }
2502 }
2503
zend_ast_is_short_circuited(const zend_ast * ast)2504 static bool zend_ast_is_short_circuited(const zend_ast *ast)
2505 {
2506 switch (ast->kind) {
2507 case ZEND_AST_DIM:
2508 case ZEND_AST_PROP:
2509 case ZEND_AST_STATIC_PROP:
2510 case ZEND_AST_METHOD_CALL:
2511 case ZEND_AST_STATIC_CALL:
2512 return zend_ast_is_short_circuited(ast->child[0]);
2513 case ZEND_AST_NULLSAFE_PROP:
2514 case ZEND_AST_NULLSAFE_METHOD_CALL:
2515 return 1;
2516 default:
2517 return 0;
2518 }
2519 }
2520
zend_assert_not_short_circuited(const zend_ast * ast)2521 static void zend_assert_not_short_circuited(const zend_ast *ast)
2522 {
2523 if (zend_ast_is_short_circuited(ast)) {
2524 zend_error_noreturn(E_COMPILE_ERROR, "Cannot take reference of a nullsafe chain");
2525 }
2526 }
2527
2528 /* Mark nodes that are an inner part of a short-circuiting chain.
2529 * We should not perform a "commit" on them, as it will be performed by the outer-most node.
2530 * We do this to avoid passing down an argument in various compile functions. */
2531
2532 #define ZEND_SHORT_CIRCUITING_INNER 0x8000
2533
zend_short_circuiting_mark_inner(zend_ast * ast)2534 static void zend_short_circuiting_mark_inner(zend_ast *ast) {
2535 if (zend_ast_kind_is_short_circuited(ast->kind)) {
2536 ast->attr |= ZEND_SHORT_CIRCUITING_INNER;
2537 }
2538 }
2539
zend_short_circuiting_checkpoint(void)2540 static uint32_t zend_short_circuiting_checkpoint(void)
2541 {
2542 return zend_stack_count(&CG(short_circuiting_opnums));
2543 }
2544
zend_short_circuiting_commit(uint32_t checkpoint,znode * result,zend_ast * ast)2545 static void zend_short_circuiting_commit(uint32_t checkpoint, znode *result, zend_ast *ast)
2546 {
2547 bool is_short_circuited = zend_ast_kind_is_short_circuited(ast->kind)
2548 || ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY;
2549 if (!is_short_circuited) {
2550 ZEND_ASSERT(zend_stack_count(&CG(short_circuiting_opnums)) == checkpoint
2551 && "Short circuiting stack should be empty");
2552 return;
2553 }
2554
2555 if (ast->attr & ZEND_SHORT_CIRCUITING_INNER) {
2556 /* Outer-most node will commit. */
2557 return;
2558 }
2559
2560 while (zend_stack_count(&CG(short_circuiting_opnums)) != checkpoint) {
2561 uint32_t opnum = *(uint32_t *) zend_stack_top(&CG(short_circuiting_opnums));
2562 zend_op *opline = &CG(active_op_array)->opcodes[opnum];
2563 opline->op2.opline_num = get_next_op_number();
2564 SET_NODE(opline->result, result);
2565 opline->extended_value |=
2566 ast->kind == ZEND_AST_ISSET ? ZEND_SHORT_CIRCUITING_CHAIN_ISSET :
2567 ast->kind == ZEND_AST_EMPTY ? ZEND_SHORT_CIRCUITING_CHAIN_EMPTY :
2568 ZEND_SHORT_CIRCUITING_CHAIN_EXPR;
2569 zend_stack_del_top(&CG(short_circuiting_opnums));
2570 }
2571 }
2572
zend_emit_jmp_null(znode * obj_node,uint32_t bp_type)2573 static void zend_emit_jmp_null(znode *obj_node, uint32_t bp_type)
2574 {
2575 uint32_t jmp_null_opnum = get_next_op_number();
2576 zend_op *opline = zend_emit_op(NULL, ZEND_JMP_NULL, obj_node, NULL);
2577 if (opline->op1_type == IS_CONST) {
2578 Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
2579 }
2580 if (bp_type == BP_VAR_IS) {
2581 opline->extended_value |= ZEND_JMP_NULL_BP_VAR_IS;
2582 }
2583 zend_stack_push(&CG(short_circuiting_opnums), &jmp_null_opnum);
2584 }
2585
zend_compile_memoized_expr(znode * result,zend_ast * expr)2586 static void zend_compile_memoized_expr(znode *result, zend_ast *expr) /* {{{ */
2587 {
2588 const zend_memoize_mode memoize_mode = CG(memoize_mode);
2589 if (memoize_mode == ZEND_MEMOIZE_COMPILE) {
2590 znode memoized_result;
2591
2592 /* Go through normal compilation */
2593 CG(memoize_mode) = ZEND_MEMOIZE_NONE;
2594 zend_compile_expr(result, expr);
2595 CG(memoize_mode) = ZEND_MEMOIZE_COMPILE;
2596
2597 if (result->op_type == IS_VAR) {
2598 zend_emit_op(&memoized_result, ZEND_COPY_TMP, result, NULL);
2599 } else if (result->op_type == IS_TMP_VAR) {
2600 zend_emit_op_tmp(&memoized_result, ZEND_COPY_TMP, result, NULL);
2601 } else {
2602 if (result->op_type == IS_CONST) {
2603 Z_TRY_ADDREF(result->u.constant);
2604 }
2605 memoized_result = *result;
2606 }
2607
2608 zend_hash_index_update_mem(
2609 CG(memoized_exprs), (uintptr_t) expr, &memoized_result, sizeof(znode));
2610 } else if (memoize_mode == ZEND_MEMOIZE_FETCH) {
2611 znode *memoized_result = zend_hash_index_find_ptr(CG(memoized_exprs), (uintptr_t) expr);
2612 *result = *memoized_result;
2613 if (result->op_type == IS_CONST) {
2614 Z_TRY_ADDREF(result->u.constant);
2615 }
2616 } else {
2617 ZEND_UNREACHABLE();
2618 }
2619 }
2620 /* }}} */
2621
2622 /* Remember to update type_num_classes() in compact_literals.c when changing this function */
zend_type_get_num_classes(zend_type type)2623 static size_t zend_type_get_num_classes(zend_type type) {
2624 if (!ZEND_TYPE_IS_COMPLEX(type)) {
2625 return 0;
2626 }
2627 if (ZEND_TYPE_HAS_LIST(type)) {
2628 /* Intersection types cannot have nested list types */
2629 if (ZEND_TYPE_IS_INTERSECTION(type)) {
2630 return ZEND_TYPE_LIST(type)->num_types;
2631 }
2632 ZEND_ASSERT(ZEND_TYPE_IS_UNION(type));
2633 size_t count = 0;
2634 zend_type *list_type;
2635
2636 ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
2637 if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
2638 count += ZEND_TYPE_LIST(*list_type)->num_types;
2639 } else {
2640 ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
2641 count += 1;
2642 }
2643 } ZEND_TYPE_LIST_FOREACH_END();
2644 return count;
2645 }
2646 return 1;
2647 }
2648
zend_emit_return_type_check(znode * expr,zend_arg_info * return_info,bool implicit)2649 static void zend_emit_return_type_check(
2650 znode *expr, zend_arg_info *return_info, bool implicit) /* {{{ */
2651 {
2652 zend_type type = return_info->type;
2653 if (ZEND_TYPE_IS_SET(type)) {
2654 zend_op *opline;
2655
2656 /* `return ...;` is illegal in a void function (but `return;` isn't) */
2657 if (ZEND_TYPE_CONTAINS_CODE(type, IS_VOID)) {
2658 if (expr) {
2659 if (expr->op_type == IS_CONST && Z_TYPE(expr->u.constant) == IS_NULL) {
2660 zend_error_noreturn(E_COMPILE_ERROR,
2661 "A void %s must not return a value "
2662 "(did you mean \"return;\" instead of \"return null;\"?)",
2663 CG(active_class_entry) != NULL ? "method" : "function");
2664 } else {
2665 zend_error_noreturn(E_COMPILE_ERROR, "A void %s must not return a value",
2666 CG(active_class_entry) != NULL ? "method" : "function");
2667 }
2668 }
2669 /* we don't need run-time check */
2670 return;
2671 }
2672
2673 /* `return` is illegal in a never-returning function */
2674 if (ZEND_TYPE_CONTAINS_CODE(type, IS_NEVER)) {
2675 /* Implicit case handled separately using VERIFY_NEVER_TYPE opcode. */
2676 ZEND_ASSERT(!implicit);
2677 zend_error_noreturn(E_COMPILE_ERROR, "A never-returning %s must not return",
2678 CG(active_class_entry) != NULL ? "method" : "function");
2679 return;
2680 }
2681
2682 if (!expr && !implicit) {
2683 if (ZEND_TYPE_ALLOW_NULL(type)) {
2684 zend_error_noreturn(E_COMPILE_ERROR,
2685 "A %s with return type must return a value "
2686 "(did you mean \"return null;\" instead of \"return;\"?)",
2687 CG(active_class_entry) != NULL ? "method" : "function");
2688 } else {
2689 zend_error_noreturn(E_COMPILE_ERROR,
2690 "A %s with return type must return a value",
2691 CG(active_class_entry) != NULL ? "method" : "function");
2692 }
2693 }
2694
2695 if (expr && ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY) {
2696 /* we don't need run-time check for mixed return type */
2697 return;
2698 }
2699
2700 if (expr && expr->op_type == IS_CONST && ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE(expr->u.constant))) {
2701 /* we don't need run-time check */
2702 return;
2703 }
2704
2705 opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL);
2706 if (expr && expr->op_type == IS_CONST) {
2707 opline->result_type = expr->op_type = IS_TMP_VAR;
2708 opline->result.var = expr->u.op.var = get_temporary_variable();
2709 }
2710
2711 opline->op2.num = zend_alloc_cache_slots(zend_type_get_num_classes(return_info->type));
2712 }
2713 }
2714 /* }}} */
2715
zend_emit_final_return(bool return_one)2716 void zend_emit_final_return(bool return_one) /* {{{ */
2717 {
2718 znode zn;
2719 zend_op *ret;
2720 bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
2721
2722 if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)
2723 && !(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR)) {
2724 zend_arg_info *return_info = CG(active_op_array)->arg_info - 1;
2725
2726 if (ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_NEVER)) {
2727 zend_emit_op(NULL, ZEND_VERIFY_NEVER_TYPE, NULL, NULL);
2728 return;
2729 }
2730
2731 zend_emit_return_type_check(NULL, return_info, 1);
2732 }
2733
2734 zn.op_type = IS_CONST;
2735 if (return_one) {
2736 ZVAL_LONG(&zn.u.constant, 1);
2737 } else {
2738 ZVAL_NULL(&zn.u.constant);
2739 }
2740
2741 ret = zend_emit_op(NULL, returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN, &zn, NULL);
2742 ret->extended_value = -1;
2743 }
2744 /* }}} */
2745
zend_is_variable(zend_ast * ast)2746 static inline bool zend_is_variable(zend_ast *ast) /* {{{ */
2747 {
2748 return ast->kind == ZEND_AST_VAR
2749 || ast->kind == ZEND_AST_DIM
2750 || ast->kind == ZEND_AST_PROP
2751 || ast->kind == ZEND_AST_NULLSAFE_PROP
2752 || ast->kind == ZEND_AST_STATIC_PROP;
2753 }
2754 /* }}} */
2755
zend_is_call(zend_ast * ast)2756 static inline bool zend_is_call(zend_ast *ast) /* {{{ */
2757 {
2758 return ast->kind == ZEND_AST_CALL
2759 || ast->kind == ZEND_AST_METHOD_CALL
2760 || ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL
2761 || ast->kind == ZEND_AST_STATIC_CALL;
2762 }
2763 /* }}} */
2764
zend_is_variable_or_call(zend_ast * ast)2765 static inline bool zend_is_variable_or_call(zend_ast *ast) /* {{{ */
2766 {
2767 return zend_is_variable(ast) || zend_is_call(ast);
2768 }
2769 /* }}} */
2770
zend_is_unticked_stmt(zend_ast * ast)2771 static inline bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
2772 {
2773 return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL
2774 || ast->kind == ZEND_AST_PROP_DECL || ast->kind == ZEND_AST_CLASS_CONST_GROUP
2775 || ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD;
2776 }
2777 /* }}} */
2778
zend_can_write_to_variable(zend_ast * ast)2779 static inline bool zend_can_write_to_variable(zend_ast *ast) /* {{{ */
2780 {
2781 while (
2782 ast->kind == ZEND_AST_DIM
2783 || ast->kind == ZEND_AST_PROP
2784 ) {
2785 ast = ast->child[0];
2786 }
2787
2788 return zend_is_variable_or_call(ast) && !zend_ast_is_short_circuited(ast);
2789 }
2790 /* }}} */
2791
zend_is_const_default_class_ref(zend_ast * name_ast)2792 static inline bool zend_is_const_default_class_ref(zend_ast *name_ast) /* {{{ */
2793 {
2794 if (name_ast->kind != ZEND_AST_ZVAL) {
2795 return 0;
2796 }
2797
2798 return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type_ast(name_ast);
2799 }
2800 /* }}} */
2801
zend_handle_numeric_op(znode * node)2802 static inline void zend_handle_numeric_op(znode *node) /* {{{ */
2803 {
2804 if (node->op_type == IS_CONST && Z_TYPE(node->u.constant) == IS_STRING) {
2805 zend_ulong index;
2806
2807 if (ZEND_HANDLE_NUMERIC(Z_STR(node->u.constant), index)) {
2808 zval_ptr_dtor(&node->u.constant);
2809 ZVAL_LONG(&node->u.constant, index);
2810 }
2811 }
2812 }
2813 /* }}} */
2814
zend_handle_numeric_dim(zend_op * opline,znode * dim_node)2815 static inline void zend_handle_numeric_dim(zend_op *opline, znode *dim_node) /* {{{ */
2816 {
2817 if (Z_TYPE(dim_node->u.constant) == IS_STRING) {
2818 zend_ulong index;
2819
2820 if (ZEND_HANDLE_NUMERIC(Z_STR(dim_node->u.constant), index)) {
2821 /* For numeric indexes we also keep the original value to use by ArrayAccess
2822 * See bug #63217
2823 */
2824 int c = zend_add_literal(&dim_node->u.constant);
2825 ZEND_ASSERT(opline->op2.constant + 1 == c);
2826 ZVAL_LONG(CT_CONSTANT(opline->op2), index);
2827 Z_EXTRA_P(CT_CONSTANT(opline->op2)) = ZEND_EXTRA_VALUE;
2828 return;
2829 }
2830 }
2831 }
2832 /* }}} */
2833
zend_set_class_name_op1(zend_op * opline,znode * class_node)2834 static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node) /* {{{ */
2835 {
2836 if (class_node->op_type == IS_CONST) {
2837 opline->op1_type = IS_CONST;
2838 opline->op1.constant = zend_add_class_name_literal(
2839 Z_STR(class_node->u.constant));
2840 } else {
2841 SET_NODE(opline->op1, class_node);
2842 }
2843 }
2844 /* }}} */
2845
zend_compile_class_ref(znode * result,zend_ast * name_ast,uint32_t fetch_flags)2846 static void zend_compile_class_ref(znode *result, zend_ast *name_ast, uint32_t fetch_flags) /* {{{ */
2847 {
2848 uint32_t fetch_type;
2849
2850 if (name_ast->kind != ZEND_AST_ZVAL) {
2851 znode name_node;
2852
2853 zend_compile_expr(&name_node, name_ast);
2854
2855 if (name_node.op_type == IS_CONST) {
2856 zend_string *name;
2857
2858 if (Z_TYPE(name_node.u.constant) != IS_STRING) {
2859 zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
2860 }
2861
2862 name = Z_STR(name_node.u.constant);
2863 fetch_type = zend_get_class_fetch_type(name);
2864
2865 if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
2866 result->op_type = IS_CONST;
2867 ZVAL_STR(&result->u.constant, zend_resolve_class_name(name, ZEND_NAME_FQ));
2868 } else {
2869 zend_ensure_valid_class_fetch_type(fetch_type);
2870 result->op_type = IS_UNUSED;
2871 result->u.op.num = fetch_type | fetch_flags;
2872 }
2873
2874 zend_string_release_ex(name, 0);
2875 } else {
2876 zend_op *opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node);
2877 opline->op1.num = ZEND_FETCH_CLASS_DEFAULT | fetch_flags;
2878 }
2879 return;
2880 }
2881
2882 /* Fully qualified names are always default refs */
2883 if (name_ast->attr == ZEND_NAME_FQ) {
2884 result->op_type = IS_CONST;
2885 ZVAL_STR(&result->u.constant, zend_resolve_class_name_ast(name_ast));
2886 return;
2887 }
2888
2889 fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
2890 if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
2891 result->op_type = IS_CONST;
2892 ZVAL_STR(&result->u.constant, zend_resolve_class_name_ast(name_ast));
2893 } else {
2894 zend_ensure_valid_class_fetch_type(fetch_type);
2895 result->op_type = IS_UNUSED;
2896 result->u.op.num = fetch_type | fetch_flags;
2897 }
2898 }
2899 /* }}} */
2900
zend_try_compile_cv(znode * result,zend_ast * ast)2901 static zend_result zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
2902 {
2903 zend_ast *name_ast = ast->child[0];
2904 if (name_ast->kind == ZEND_AST_ZVAL) {
2905 zval *zv = zend_ast_get_zval(name_ast);
2906 zend_string *name;
2907
2908 if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
2909 name = zval_make_interned_string(zv);
2910 } else {
2911 name = zend_new_interned_string(zval_get_string_func(zv));
2912 }
2913
2914 if (zend_is_auto_global(name)) {
2915 return FAILURE;
2916 }
2917
2918 result->op_type = IS_CV;
2919 result->u.op.var = lookup_cv(name);
2920
2921 if (UNEXPECTED(Z_TYPE_P(zv) != IS_STRING)) {
2922 zend_string_release_ex(name, 0);
2923 }
2924
2925 return SUCCESS;
2926 }
2927
2928 return FAILURE;
2929 }
2930 /* }}} */
2931
zend_compile_simple_var_no_cv(znode * result,zend_ast * ast,uint32_t type,bool delayed)2932 static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint32_t type, bool delayed) /* {{{ */
2933 {
2934 zend_ast *name_ast = ast->child[0];
2935 znode name_node;
2936 zend_op *opline;
2937
2938 zend_compile_expr(&name_node, name_ast);
2939 if (name_node.op_type == IS_CONST) {
2940 convert_to_string(&name_node.u.constant);
2941 }
2942
2943 if (delayed) {
2944 opline = zend_delayed_emit_op(result, ZEND_FETCH_R, &name_node, NULL);
2945 } else {
2946 opline = zend_emit_op(result, ZEND_FETCH_R, &name_node, NULL);
2947 }
2948
2949 if (name_node.op_type == IS_CONST &&
2950 zend_is_auto_global(Z_STR(name_node.u.constant))) {
2951
2952 opline->extended_value = ZEND_FETCH_GLOBAL;
2953 } else {
2954 opline->extended_value = ZEND_FETCH_LOCAL;
2955 }
2956
2957 zend_adjust_for_fetch_type(opline, result, type);
2958 return opline;
2959 }
2960 /* }}} */
2961
is_this_fetch(zend_ast * ast)2962 static bool is_this_fetch(zend_ast *ast) /* {{{ */
2963 {
2964 if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
2965 zval *name = zend_ast_get_zval(ast->child[0]);
2966 return Z_TYPE_P(name) == IS_STRING && zend_string_equals(Z_STR_P(name), ZSTR_KNOWN(ZEND_STR_THIS));
2967 }
2968
2969 return 0;
2970 }
2971 /* }}} */
2972
is_globals_fetch(const zend_ast * ast)2973 static bool is_globals_fetch(const zend_ast *ast)
2974 {
2975 if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
2976 zval *name = zend_ast_get_zval(ast->child[0]);
2977 return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "GLOBALS");
2978 }
2979
2980 return 0;
2981 }
2982
is_global_var_fetch(zend_ast * ast)2983 static bool is_global_var_fetch(zend_ast *ast)
2984 {
2985 return ast->kind == ZEND_AST_DIM && is_globals_fetch(ast->child[0]);
2986 }
2987
this_guaranteed_exists(void)2988 static bool this_guaranteed_exists(void) /* {{{ */
2989 {
2990 zend_oparray_context *ctx = &CG(context);
2991 while (ctx) {
2992 /* Instance methods always have a $this.
2993 * This also includes closures that have a scope and use $this. */
2994 zend_op_array *op_array = ctx->op_array;
2995 if (op_array->fn_flags & ZEND_ACC_STATIC) {
2996 return false;
2997 } else if (op_array->scope) {
2998 return true;
2999 } else if (!(op_array->fn_flags & ZEND_ACC_CLOSURE)) {
3000 return false;
3001 }
3002 ctx = ctx->prev;
3003 }
3004 return false;
3005 }
3006 /* }}} */
3007
zend_compile_simple_var(znode * result,zend_ast * ast,uint32_t type,bool delayed)3008 static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, bool delayed) /* {{{ */
3009 {
3010 if (is_this_fetch(ast)) {
3011 zend_op *opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL);
3012 if ((type == BP_VAR_R) || (type == BP_VAR_IS)) {
3013 opline->result_type = IS_TMP_VAR;
3014 result->op_type = IS_TMP_VAR;
3015 }
3016 CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
3017 return opline;
3018 } else if (is_globals_fetch(ast)) {
3019 zend_op *opline = zend_emit_op(result, ZEND_FETCH_GLOBALS, NULL, NULL);
3020 if (type == BP_VAR_R || type == BP_VAR_IS) {
3021 opline->result_type = IS_TMP_VAR;
3022 result->op_type = IS_TMP_VAR;
3023 }
3024 return opline;
3025 } else if (zend_try_compile_cv(result, ast) == FAILURE) {
3026 return zend_compile_simple_var_no_cv(result, ast, type, delayed);
3027 }
3028 return NULL;
3029 }
3030 /* }}} */
3031
zend_separate_if_call_and_write(znode * node,zend_ast * ast,uint32_t type)3032 static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type) /* {{{ */
3033 {
3034 if (type != BP_VAR_R
3035 && type != BP_VAR_IS
3036 /* Whether a FUNC_ARG is R may only be determined at runtime. */
3037 && type != BP_VAR_FUNC_ARG
3038 && zend_is_call(ast)) {
3039 if (node->op_type == IS_VAR) {
3040 zend_op *opline = zend_emit_op(NULL, ZEND_SEPARATE, node, NULL);
3041 opline->result_type = IS_VAR;
3042 opline->result.var = opline->op1.var;
3043 } else {
3044 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
3045 }
3046 }
3047 }
3048 /* }}} */
3049
zend_emit_assign_znode(zend_ast * var_ast,znode * value_node)3050 static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) /* {{{ */
3051 {
3052 znode dummy_node;
3053 zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
3054 zend_ast_create_znode(value_node));
3055 zend_compile_expr(&dummy_node, assign_ast);
3056 zend_do_free(&dummy_node);
3057 }
3058 /* }}} */
3059
zend_delayed_compile_dim(znode * result,zend_ast * ast,uint32_t type,bool by_ref)3060 static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type, bool by_ref)
3061 {
3062 zend_ast *var_ast = ast->child[0];
3063 zend_ast *dim_ast = ast->child[1];
3064 zend_op *opline;
3065
3066 znode var_node, dim_node;
3067
3068 if (is_globals_fetch(var_ast)) {
3069 if (dim_ast == NULL) {
3070 zend_error_noreturn(E_COMPILE_ERROR, "Cannot append to $GLOBALS");
3071 }
3072
3073 zend_compile_expr(&dim_node, dim_ast);
3074 if (dim_node.op_type == IS_CONST) {
3075 convert_to_string(&dim_node.u.constant);
3076 }
3077
3078 opline = zend_delayed_emit_op(result, ZEND_FETCH_R, &dim_node, NULL);
3079 opline->extended_value = ZEND_FETCH_GLOBAL;
3080 zend_adjust_for_fetch_type(opline, result, type);
3081 return opline;
3082 } else {
3083 zend_short_circuiting_mark_inner(var_ast);
3084 opline = zend_delayed_compile_var(&var_node, var_ast, type, 0);
3085 if (opline) {
3086 if (type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
3087 opline->extended_value |= ZEND_FETCH_DIM_WRITE;
3088 } else if (opline->opcode == ZEND_FETCH_DIM_W
3089 || opline->opcode == ZEND_FETCH_DIM_RW
3090 || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
3091 || opline->opcode == ZEND_FETCH_DIM_UNSET) {
3092 opline->extended_value = ZEND_FETCH_DIM_DIM;
3093 }
3094 }
3095 }
3096
3097 zend_separate_if_call_and_write(&var_node, var_ast, type);
3098
3099 if (dim_ast == NULL) {
3100 if (type == BP_VAR_R || type == BP_VAR_IS) {
3101 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
3102 }
3103 if (type == BP_VAR_UNSET) {
3104 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for unsetting");
3105 }
3106 dim_node.op_type = IS_UNUSED;
3107 } else {
3108 zend_compile_expr(&dim_node, dim_ast);
3109 }
3110
3111 opline = zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node);
3112 zend_adjust_for_fetch_type(opline, result, type);
3113 if (by_ref) {
3114 opline->extended_value = ZEND_FETCH_DIM_REF;
3115 }
3116
3117 if (dim_node.op_type == IS_CONST) {
3118 zend_handle_numeric_dim(opline, &dim_node);
3119 }
3120 return opline;
3121 }
3122
zend_compile_dim(znode * result,zend_ast * ast,uint32_t type,bool by_ref)3123 static zend_op *zend_compile_dim(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
3124 {
3125 uint32_t offset = zend_delayed_compile_begin();
3126 zend_delayed_compile_dim(result, ast, type, by_ref);
3127 return zend_delayed_compile_end(offset);
3128 }
3129 /* }}} */
3130
zend_delayed_compile_prop(znode * result,zend_ast * ast,uint32_t type)3131 static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
3132 {
3133 zend_ast *obj_ast = ast->child[0];
3134 zend_ast *prop_ast = ast->child[1];
3135
3136 znode obj_node, prop_node;
3137 zend_op *opline;
3138 bool nullsafe = ast->kind == ZEND_AST_NULLSAFE_PROP;
3139
3140 if (is_this_fetch(obj_ast)) {
3141 if (this_guaranteed_exists()) {
3142 obj_node.op_type = IS_UNUSED;
3143 } else {
3144 zend_emit_op(&obj_node, ZEND_FETCH_THIS, NULL, NULL);
3145 }
3146 CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
3147
3148 /* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
3149 * check for a nullsafe access. */
3150 } else {
3151 zend_short_circuiting_mark_inner(obj_ast);
3152 opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
3153 if (opline && (opline->opcode == ZEND_FETCH_DIM_W
3154 || opline->opcode == ZEND_FETCH_DIM_RW
3155 || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
3156 || opline->opcode == ZEND_FETCH_DIM_UNSET)) {
3157 opline->extended_value = ZEND_FETCH_DIM_OBJ;
3158 }
3159
3160 zend_separate_if_call_and_write(&obj_node, obj_ast, type);
3161 if (nullsafe) {
3162 if (obj_node.op_type == IS_TMP_VAR) {
3163 /* Flush delayed oplines */
3164 zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
3165 uint32_t var = obj_node.u.op.var;
3166 uint32_t count = zend_stack_count(&CG(delayed_oplines_stack));
3167 uint32_t i = count;
3168
3169 while (i > 0 && oplines[i-1].result_type == IS_TMP_VAR && oplines[i-1].result.var == var) {
3170 i--;
3171 if (oplines[i].op1_type == IS_TMP_VAR) {
3172 var = oplines[i].op1.var;
3173 } else {
3174 break;
3175 }
3176 }
3177 for (; i < count; ++i) {
3178 if (oplines[i].opcode != ZEND_NOP) {
3179 opline = get_next_op();
3180 memcpy(opline, &oplines[i], sizeof(zend_op));
3181 oplines[i].opcode = ZEND_NOP;
3182 oplines[i].extended_value = opline - CG(active_op_array)->opcodes;
3183 }
3184 }
3185 }
3186 zend_emit_jmp_null(&obj_node, type);
3187 }
3188 }
3189
3190 zend_compile_expr(&prop_node, prop_ast);
3191
3192 opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node);
3193 if (opline->op2_type == IS_CONST) {
3194 convert_to_string(CT_CONSTANT(opline->op2));
3195 zend_string_hash_val(Z_STR_P(CT_CONSTANT(opline->op2)));
3196 opline->extended_value = zend_alloc_cache_slots(3);
3197 }
3198
3199 zend_adjust_for_fetch_type(opline, result, type);
3200
3201 return opline;
3202 }
3203 /* }}} */
3204
zend_compile_prop(znode * result,zend_ast * ast,uint32_t type,bool by_ref)3205 static zend_op *zend_compile_prop(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
3206 {
3207 uint32_t offset = zend_delayed_compile_begin();
3208 zend_op *opline = zend_delayed_compile_prop(result, ast, type);
3209 if (by_ref) { /* shared with cache_slot */
3210 opline->extended_value |= ZEND_FETCH_REF;
3211 }
3212 return zend_delayed_compile_end(offset);
3213 }
3214 /* }}} */
3215
zend_compile_static_prop(znode * result,zend_ast * ast,uint32_t type,bool by_ref,bool delayed)3216 static zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, bool by_ref, bool delayed) /* {{{ */
3217 {
3218 zend_ast *class_ast = ast->child[0];
3219 zend_ast *prop_ast = ast->child[1];
3220
3221 znode class_node, prop_node;
3222 zend_op *opline;
3223
3224 zend_short_circuiting_mark_inner(class_ast);
3225 zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
3226
3227 zend_compile_expr(&prop_node, prop_ast);
3228
3229 if (delayed) {
3230 opline = zend_delayed_emit_op(result, ZEND_FETCH_STATIC_PROP_R, &prop_node, NULL);
3231 } else {
3232 opline = zend_emit_op(result, ZEND_FETCH_STATIC_PROP_R, &prop_node, NULL);
3233 }
3234 if (opline->op1_type == IS_CONST) {
3235 convert_to_string(CT_CONSTANT(opline->op1));
3236 opline->extended_value = zend_alloc_cache_slots(3);
3237 }
3238 if (class_node.op_type == IS_CONST) {
3239 opline->op2_type = IS_CONST;
3240 opline->op2.constant = zend_add_class_name_literal(
3241 Z_STR(class_node.u.constant));
3242 if (opline->op1_type != IS_CONST) {
3243 opline->extended_value = zend_alloc_cache_slot();
3244 }
3245 } else {
3246 SET_NODE(opline->op2, &class_node);
3247 }
3248
3249 if (by_ref && (type == BP_VAR_W || type == BP_VAR_FUNC_ARG)) { /* shared with cache_slot */
3250 opline->extended_value |= ZEND_FETCH_REF;
3251 }
3252
3253 zend_adjust_for_fetch_type(opline, result, type);
3254 return opline;
3255 }
3256 /* }}} */
3257
zend_verify_list_assign_target(zend_ast * var_ast,zend_ast_attr array_style)3258 static void zend_verify_list_assign_target(zend_ast *var_ast, zend_ast_attr array_style) /* {{{ */ {
3259 if (var_ast->kind == ZEND_AST_ARRAY) {
3260 if (var_ast->attr == ZEND_ARRAY_SYNTAX_LONG) {
3261 zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign to array(), use [] instead");
3262 }
3263 if (array_style != var_ast->attr) {
3264 zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix [] and list()");
3265 }
3266 } else if (!zend_can_write_to_variable(var_ast)) {
3267 zend_error_noreturn(E_COMPILE_ERROR, "Assignments can only happen to writable values");
3268 }
3269 }
3270 /* }}} */
3271
3272 static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node);
3273
3274 /* Propagate refs used on leaf elements to the surrounding list() structures. */
zend_propagate_list_refs(zend_ast * ast)3275 static bool zend_propagate_list_refs(zend_ast *ast) { /* {{{ */
3276 zend_ast_list *list = zend_ast_get_list(ast);
3277 bool has_refs = 0;
3278 uint32_t i;
3279
3280 for (i = 0; i < list->children; ++i) {
3281 zend_ast *elem_ast = list->child[i];
3282
3283 if (elem_ast) {
3284 zend_ast *var_ast = elem_ast->child[0];
3285 if (var_ast->kind == ZEND_AST_ARRAY) {
3286 elem_ast->attr = zend_propagate_list_refs(var_ast);
3287 }
3288 has_refs |= elem_ast->attr;
3289 }
3290 }
3291
3292 return has_refs;
3293 }
3294 /* }}} */
3295
list_is_keyed(zend_ast_list * list)3296 static bool list_is_keyed(zend_ast_list *list)
3297 {
3298 for (uint32_t i = 0; i < list->children; i++) {
3299 zend_ast *child = list->child[i];
3300 if (child) {
3301 return child->kind == ZEND_AST_ARRAY_ELEM && child->child[1] != NULL;
3302 }
3303 }
3304 return false;
3305 }
3306
zend_compile_list_assign(znode * result,zend_ast * ast,znode * expr_node,zend_ast_attr array_style)3307 static void zend_compile_list_assign(
3308 znode *result, zend_ast *ast, znode *expr_node, zend_ast_attr array_style) /* {{{ */
3309 {
3310 zend_ast_list *list = zend_ast_get_list(ast);
3311 uint32_t i;
3312 bool has_elems = 0;
3313 bool is_keyed = list_is_keyed(list);
3314
3315 if (list->children && expr_node->op_type == IS_CONST && Z_TYPE(expr_node->u.constant) == IS_STRING) {
3316 zval_make_interned_string(&expr_node->u.constant);
3317 }
3318
3319 for (i = 0; i < list->children; ++i) {
3320 zend_ast *elem_ast = list->child[i];
3321 zend_ast *var_ast, *key_ast;
3322 znode fetch_result, dim_node;
3323 zend_op *opline;
3324
3325 if (elem_ast == NULL) {
3326 if (is_keyed) {
3327 zend_error(E_COMPILE_ERROR,
3328 "Cannot use empty array entries in keyed array assignment");
3329 } else {
3330 continue;
3331 }
3332 }
3333
3334 if (elem_ast->kind == ZEND_AST_UNPACK) {
3335 zend_error(E_COMPILE_ERROR,
3336 "Spread operator is not supported in assignments");
3337 }
3338
3339 var_ast = elem_ast->child[0];
3340 key_ast = elem_ast->child[1];
3341 has_elems = 1;
3342
3343 if (is_keyed) {
3344 if (key_ast == NULL) {
3345 zend_error(E_COMPILE_ERROR,
3346 "Cannot mix keyed and unkeyed array entries in assignments");
3347 }
3348
3349 zend_compile_expr(&dim_node, key_ast);
3350 } else {
3351 if (key_ast != NULL) {
3352 zend_error(E_COMPILE_ERROR,
3353 "Cannot mix keyed and unkeyed array entries in assignments");
3354 }
3355
3356 dim_node.op_type = IS_CONST;
3357 ZVAL_LONG(&dim_node.u.constant, i);
3358 }
3359
3360 if (expr_node->op_type == IS_CONST) {
3361 Z_TRY_ADDREF(expr_node->u.constant);
3362 }
3363
3364 zend_verify_list_assign_target(var_ast, array_style);
3365
3366 opline = zend_emit_op(&fetch_result,
3367 elem_ast->attr ? (expr_node->op_type == IS_CV ? ZEND_FETCH_DIM_W : ZEND_FETCH_LIST_W) : ZEND_FETCH_LIST_R, expr_node, &dim_node);
3368
3369 if (dim_node.op_type == IS_CONST) {
3370 zend_handle_numeric_dim(opline, &dim_node);
3371 }
3372
3373 if (elem_ast->attr) {
3374 zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL);
3375 }
3376 if (var_ast->kind == ZEND_AST_ARRAY) {
3377 zend_compile_list_assign(NULL, var_ast, &fetch_result, var_ast->attr);
3378 } else if (elem_ast->attr) {
3379 zend_emit_assign_ref_znode(var_ast, &fetch_result);
3380 } else {
3381 zend_emit_assign_znode(var_ast, &fetch_result);
3382 }
3383 }
3384
3385 if (has_elems == 0) {
3386 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list");
3387 }
3388
3389 if (result) {
3390 *result = *expr_node;
3391 } else {
3392 zend_do_free(expr_node);
3393 }
3394 }
3395 /* }}} */
3396
zend_ensure_writable_variable(const zend_ast * ast)3397 static void zend_ensure_writable_variable(const zend_ast *ast) /* {{{ */
3398 {
3399 if (ast->kind == ZEND_AST_CALL) {
3400 zend_error_noreturn(E_COMPILE_ERROR, "Can't use function return value in write context");
3401 }
3402 if (
3403 ast->kind == ZEND_AST_METHOD_CALL
3404 || ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL
3405 || ast->kind == ZEND_AST_STATIC_CALL
3406 ) {
3407 zend_error_noreturn(E_COMPILE_ERROR, "Can't use method return value in write context");
3408 }
3409 if (zend_ast_is_short_circuited(ast)) {
3410 zend_error_noreturn(E_COMPILE_ERROR, "Can't use nullsafe operator in write context");
3411 }
3412 if (is_globals_fetch(ast)) {
3413 zend_error_noreturn(E_COMPILE_ERROR,
3414 "$GLOBALS can only be modified using the $GLOBALS[$name] = $value syntax");
3415 }
3416 }
3417 /* }}} */
3418
3419 /* Detects $a... = $a pattern */
zend_is_assign_to_self(zend_ast * var_ast,zend_ast * expr_ast)3420 static bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast) /* {{{ */
3421 {
3422 if (expr_ast->kind != ZEND_AST_VAR || expr_ast->child[0]->kind != ZEND_AST_ZVAL) {
3423 return 0;
3424 }
3425
3426 while (zend_is_variable(var_ast) && var_ast->kind != ZEND_AST_VAR) {
3427 var_ast = var_ast->child[0];
3428 }
3429
3430 if (var_ast->kind != ZEND_AST_VAR || var_ast->child[0]->kind != ZEND_AST_ZVAL) {
3431 return 0;
3432 }
3433
3434 {
3435 zend_string *name1 = zval_get_string(zend_ast_get_zval(var_ast->child[0]));
3436 zend_string *name2 = zval_get_string(zend_ast_get_zval(expr_ast->child[0]));
3437 bool result = zend_string_equals(name1, name2);
3438 zend_string_release_ex(name1, 0);
3439 zend_string_release_ex(name2, 0);
3440 return result;
3441 }
3442 }
3443 /* }}} */
3444
zend_compile_expr_with_potential_assign_to_self(znode * expr_node,zend_ast * expr_ast,zend_ast * var_ast)3445 static void zend_compile_expr_with_potential_assign_to_self(
3446 znode *expr_node, zend_ast *expr_ast, zend_ast *var_ast) {
3447 if (zend_is_assign_to_self(var_ast, expr_ast) && !is_this_fetch(expr_ast)) {
3448 /* $a[0] = $a should evaluate the right $a first */
3449 znode cv_node;
3450
3451 if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
3452 zend_compile_simple_var_no_cv(expr_node, expr_ast, BP_VAR_R, 0);
3453 } else {
3454 zend_emit_op_tmp(expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
3455 }
3456 } else {
3457 zend_compile_expr(expr_node, expr_ast);
3458 }
3459 }
3460
zend_compile_assign(znode * result,zend_ast * ast)3461 static void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
3462 {
3463 zend_ast *var_ast = ast->child[0];
3464 zend_ast *expr_ast = ast->child[1];
3465
3466 znode var_node, expr_node;
3467 zend_op *opline;
3468 uint32_t offset;
3469 if (is_this_fetch(var_ast)) {
3470 zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3471 }
3472
3473 zend_ensure_writable_variable(var_ast);
3474
3475 /* Treat $GLOBALS['x'] assignment like assignment to variable. */
3476 zend_ast_kind kind = is_global_var_fetch(var_ast) ? ZEND_AST_VAR : var_ast->kind;
3477 switch (kind) {
3478 case ZEND_AST_VAR:
3479 offset = zend_delayed_compile_begin();
3480 zend_delayed_compile_var(&var_node, var_ast, BP_VAR_W, 0);
3481 zend_compile_expr(&expr_node, expr_ast);
3482 zend_delayed_compile_end(offset);
3483 CG(zend_lineno) = zend_ast_get_lineno(var_ast);
3484 zend_emit_op_tmp(result, ZEND_ASSIGN, &var_node, &expr_node);
3485 return;
3486 case ZEND_AST_STATIC_PROP:
3487 offset = zend_delayed_compile_begin();
3488 zend_delayed_compile_var(result, var_ast, BP_VAR_W, 0);
3489 zend_compile_expr(&expr_node, expr_ast);
3490
3491 opline = zend_delayed_compile_end(offset);
3492 opline->opcode = ZEND_ASSIGN_STATIC_PROP;
3493 opline->result_type = IS_TMP_VAR;
3494 result->op_type = IS_TMP_VAR;
3495
3496 zend_emit_op_data(&expr_node);
3497 return;
3498 case ZEND_AST_DIM:
3499 offset = zend_delayed_compile_begin();
3500 zend_delayed_compile_dim(result, var_ast, BP_VAR_W, /* by_ref */ false);
3501 zend_compile_expr_with_potential_assign_to_self(&expr_node, expr_ast, var_ast);
3502
3503 opline = zend_delayed_compile_end(offset);
3504 opline->opcode = ZEND_ASSIGN_DIM;
3505 opline->result_type = IS_TMP_VAR;
3506 result->op_type = IS_TMP_VAR;
3507
3508 opline = zend_emit_op_data(&expr_node);
3509 return;
3510 case ZEND_AST_PROP:
3511 case ZEND_AST_NULLSAFE_PROP:
3512 offset = zend_delayed_compile_begin();
3513 zend_delayed_compile_prop(result, var_ast, BP_VAR_W);
3514 zend_compile_expr(&expr_node, expr_ast);
3515
3516 opline = zend_delayed_compile_end(offset);
3517 opline->opcode = ZEND_ASSIGN_OBJ;
3518 opline->result_type = IS_TMP_VAR;
3519 result->op_type = IS_TMP_VAR;
3520
3521 zend_emit_op_data(&expr_node);
3522 return;
3523 case ZEND_AST_ARRAY:
3524 if (zend_propagate_list_refs(var_ast)) {
3525 if (!zend_is_variable_or_call(expr_ast)) {
3526 zend_error_noreturn(E_COMPILE_ERROR,
3527 "Cannot assign reference to non referenceable value");
3528 } else {
3529 zend_assert_not_short_circuited(expr_ast);
3530 }
3531
3532 zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
3533 /* MAKE_REF is usually not necessary for CVs. However, if there are
3534 * self-assignments, this forces the RHS to evaluate first. */
3535 zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL);
3536 } else {
3537 if (expr_ast->kind == ZEND_AST_VAR) {
3538 /* list($a, $b) = $a should evaluate the right $a first */
3539 znode cv_node;
3540
3541 if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
3542 zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
3543 } else {
3544 zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
3545 }
3546 } else {
3547 zend_compile_expr(&expr_node, expr_ast);
3548 }
3549 }
3550
3551 zend_compile_list_assign(result, var_ast, &expr_node, var_ast->attr);
3552 return;
3553 EMPTY_SWITCH_DEFAULT_CASE();
3554 }
3555 }
3556 /* }}} */
3557
zend_compile_assign_ref(znode * result,zend_ast * ast)3558 static void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
3559 {
3560 zend_ast *target_ast = ast->child[0];
3561 zend_ast *source_ast = ast->child[1];
3562
3563 znode target_node, source_node;
3564 zend_op *opline;
3565 uint32_t offset, flags;
3566
3567 if (is_this_fetch(target_ast)) {
3568 zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
3569 }
3570 zend_ensure_writable_variable(target_ast);
3571 zend_assert_not_short_circuited(source_ast);
3572 if (is_globals_fetch(source_ast)) {
3573 zend_error_noreturn(E_COMPILE_ERROR, "Cannot acquire reference to $GLOBALS");
3574 }
3575
3576 offset = zend_delayed_compile_begin();
3577 zend_delayed_compile_var(&target_node, target_ast, BP_VAR_W, 1);
3578 zend_compile_var(&source_node, source_ast, BP_VAR_W, 1);
3579
3580 if ((target_ast->kind != ZEND_AST_VAR
3581 || target_ast->child[0]->kind != ZEND_AST_ZVAL)
3582 && source_ast->kind != ZEND_AST_ZNODE
3583 && source_node.op_type != IS_CV) {
3584 /* Both LHS and RHS expressions may modify the same data structure,
3585 * and the modification during RHS evaluation may dangle the pointer
3586 * to the result of the LHS evaluation.
3587 * Use MAKE_REF instruction to replace direct pointer with REFERENCE.
3588 * See: Bug #71539
3589 */
3590 zend_emit_op(&source_node, ZEND_MAKE_REF, &source_node, NULL);
3591 }
3592
3593 opline = zend_delayed_compile_end(offset);
3594
3595 if (source_node.op_type != IS_VAR && zend_is_call(source_ast)) {
3596 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
3597 }
3598
3599 flags = zend_is_call(source_ast) ? ZEND_RETURNS_FUNCTION : 0;
3600
3601 if (opline && opline->opcode == ZEND_FETCH_OBJ_W) {
3602 opline->opcode = ZEND_ASSIGN_OBJ_REF;
3603 opline->extended_value &= ~ZEND_FETCH_REF;
3604 opline->extended_value |= flags;
3605 zend_emit_op_data(&source_node);
3606 *result = target_node;
3607 } else if (opline && opline->opcode == ZEND_FETCH_STATIC_PROP_W) {
3608 opline->opcode = ZEND_ASSIGN_STATIC_PROP_REF;
3609 opline->extended_value &= ~ZEND_FETCH_REF;
3610 opline->extended_value |= flags;
3611 zend_emit_op_data(&source_node);
3612 *result = target_node;
3613 } else {
3614 opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node);
3615 opline->extended_value = flags;
3616 }
3617 }
3618 /* }}} */
3619
zend_emit_assign_ref_znode(zend_ast * var_ast,znode * value_node)3620 static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node) /* {{{ */
3621 {
3622 znode dummy_node;
3623 zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN_REF, var_ast,
3624 zend_ast_create_znode(value_node));
3625 zend_compile_expr(&dummy_node, assign_ast);
3626 zend_do_free(&dummy_node);
3627 }
3628 /* }}} */
3629
zend_compile_compound_assign(znode * result,zend_ast * ast)3630 static void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
3631 {
3632 zend_ast *var_ast = ast->child[0];
3633 zend_ast *expr_ast = ast->child[1];
3634 uint32_t opcode = ast->attr;
3635
3636 znode var_node, expr_node;
3637 zend_op *opline;
3638 uint32_t offset, cache_slot;
3639
3640 zend_ensure_writable_variable(var_ast);
3641
3642 /* Treat $GLOBALS['x'] assignment like assignment to variable. */
3643 zend_ast_kind kind = is_global_var_fetch(var_ast) ? ZEND_AST_VAR : var_ast->kind;
3644 switch (kind) {
3645 case ZEND_AST_VAR:
3646 offset = zend_delayed_compile_begin();
3647 zend_delayed_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
3648 zend_compile_expr(&expr_node, expr_ast);
3649 zend_delayed_compile_end(offset);
3650 opline = zend_emit_op_tmp(result, ZEND_ASSIGN_OP, &var_node, &expr_node);
3651 opline->extended_value = opcode;
3652 return;
3653 case ZEND_AST_STATIC_PROP:
3654 offset = zend_delayed_compile_begin();
3655 zend_delayed_compile_var(result, var_ast, BP_VAR_RW, 0);
3656 zend_compile_expr(&expr_node, expr_ast);
3657
3658 opline = zend_delayed_compile_end(offset);
3659 cache_slot = opline->extended_value;
3660 opline->opcode = ZEND_ASSIGN_STATIC_PROP_OP;
3661 opline->extended_value = opcode;
3662 opline->result_type = IS_TMP_VAR;
3663 result->op_type = IS_TMP_VAR;
3664
3665 opline = zend_emit_op_data(&expr_node);
3666 opline->extended_value = cache_slot;
3667 return;
3668 case ZEND_AST_DIM:
3669 offset = zend_delayed_compile_begin();
3670 zend_delayed_compile_dim(result, var_ast, BP_VAR_RW, /* by_ref */ false);
3671 zend_compile_expr_with_potential_assign_to_self(&expr_node, expr_ast, var_ast);
3672
3673 opline = zend_delayed_compile_end(offset);
3674 opline->opcode = ZEND_ASSIGN_DIM_OP;
3675 opline->extended_value = opcode;
3676 opline->result_type = IS_TMP_VAR;
3677 result->op_type = IS_TMP_VAR;
3678
3679 zend_emit_op_data(&expr_node);
3680 return;
3681 case ZEND_AST_PROP:
3682 case ZEND_AST_NULLSAFE_PROP:
3683 offset = zend_delayed_compile_begin();
3684 zend_delayed_compile_prop(result, var_ast, BP_VAR_RW);
3685 zend_compile_expr(&expr_node, expr_ast);
3686
3687 opline = zend_delayed_compile_end(offset);
3688 cache_slot = opline->extended_value;
3689 opline->opcode = ZEND_ASSIGN_OBJ_OP;
3690 opline->extended_value = opcode;
3691 opline->result_type = IS_TMP_VAR;
3692 result->op_type = IS_TMP_VAR;
3693
3694 opline = zend_emit_op_data(&expr_node);
3695 opline->extended_value = cache_slot;
3696 return;
3697 EMPTY_SWITCH_DEFAULT_CASE()
3698 }
3699 }
3700 /* }}} */
3701
zend_get_arg_num(zend_function * fn,zend_string * arg_name)3702 static uint32_t zend_get_arg_num(zend_function *fn, zend_string *arg_name) {
3703 // TODO: Caching?
3704 if (fn->type == ZEND_USER_FUNCTION) {
3705 for (uint32_t i = 0; i < fn->common.num_args; i++) {
3706 zend_arg_info *arg_info = &fn->op_array.arg_info[i];
3707 if (zend_string_equals(arg_info->name, arg_name)) {
3708 return i + 1;
3709 }
3710 }
3711 } else {
3712 for (uint32_t i = 0; i < fn->common.num_args; i++) {
3713 zend_internal_arg_info *arg_info = &fn->internal_function.arg_info[i];
3714 size_t len = strlen(arg_info->name);
3715 if (zend_string_equals_cstr(arg_name, arg_info->name, len)) {
3716 return i + 1;
3717 }
3718 }
3719 }
3720
3721 /* Either an invalid argument name, or collected into a variadic argument. */
3722 return (uint32_t) -1;
3723 }
3724
zend_compile_args(zend_ast * ast,zend_function * fbc,bool * may_have_extra_named_args)3725 static uint32_t zend_compile_args(
3726 zend_ast *ast, zend_function *fbc, bool *may_have_extra_named_args) /* {{{ */
3727 {
3728 zend_ast_list *args = zend_ast_get_list(ast);
3729 uint32_t i;
3730 bool uses_arg_unpack = 0;
3731 uint32_t arg_count = 0; /* number of arguments not including unpacks */
3732
3733 /* Whether named arguments are used syntactically, to enforce language level limitations.
3734 * May not actually use named argument passing. */
3735 bool uses_named_args = 0;
3736 /* Whether there may be any undef arguments due to the use of named arguments. */
3737 bool may_have_undef = 0;
3738 /* Whether there may be any extra named arguments collected into a variadic. */
3739 *may_have_extra_named_args = 0;
3740
3741 for (i = 0; i < args->children; ++i) {
3742 zend_ast *arg = args->child[i];
3743 zend_string *arg_name = NULL;
3744 uint32_t arg_num = i + 1;
3745
3746 znode arg_node;
3747 zend_op *opline;
3748 uint8_t opcode;
3749
3750 if (arg->kind == ZEND_AST_UNPACK) {
3751 if (uses_named_args) {
3752 zend_error_noreturn(E_COMPILE_ERROR,
3753 "Cannot use argument unpacking after named arguments");
3754 }
3755
3756 uses_arg_unpack = 1;
3757 fbc = NULL;
3758
3759 zend_compile_expr(&arg_node, arg->child[0]);
3760 opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL);
3761 opline->op2.num = arg_count;
3762 opline->result.var = EX_NUM_TO_VAR(arg_count - 1);
3763
3764 /* Unpack may contain named arguments. */
3765 may_have_undef = 1;
3766 if (!fbc || (fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
3767 *may_have_extra_named_args = 1;
3768 }
3769 continue;
3770 }
3771
3772 if (arg->kind == ZEND_AST_NAMED_ARG) {
3773 uses_named_args = 1;
3774 arg_name = zval_make_interned_string(zend_ast_get_zval(arg->child[0]));
3775 arg = arg->child[1];
3776
3777 if (fbc && !uses_arg_unpack) {
3778 arg_num = zend_get_arg_num(fbc, arg_name);
3779 if (arg_num == arg_count + 1 && !may_have_undef) {
3780 /* Using named arguments, but passing in order. */
3781 arg_name = NULL;
3782 arg_count++;
3783 } else {
3784 // TODO: We could track which arguments were passed, even if out of order.
3785 may_have_undef = 1;
3786 if (arg_num == (uint32_t) -1 && (fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
3787 *may_have_extra_named_args = 1;
3788 }
3789 }
3790 } else {
3791 arg_num = (uint32_t) -1;
3792 may_have_undef = 1;
3793 *may_have_extra_named_args = 1;
3794 }
3795 } else {
3796 if (uses_arg_unpack) {
3797 zend_error_noreturn(E_COMPILE_ERROR,
3798 "Cannot use positional argument after argument unpacking");
3799 }
3800
3801 if (uses_named_args) {
3802 zend_error_noreturn(E_COMPILE_ERROR,
3803 "Cannot use positional argument after named argument");
3804 }
3805
3806 arg_count++;
3807 }
3808
3809 /* Treat passing of $GLOBALS the same as passing a call.
3810 * This will error at runtime if the argument is by-ref. */
3811 if (zend_is_call(arg) || is_globals_fetch(arg)) {
3812 zend_compile_var(&arg_node, arg, BP_VAR_R, 0);
3813 if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) {
3814 /* Function call was converted into builtin instruction */
3815 if (!fbc || ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
3816 opcode = ZEND_SEND_VAL_EX;
3817 } else {
3818 opcode = ZEND_SEND_VAL;
3819 }
3820 } else {
3821 if (fbc && arg_num != (uint32_t) -1) {
3822 if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
3823 opcode = ZEND_SEND_VAR_NO_REF;
3824 } else if (ARG_MAY_BE_SENT_BY_REF(fbc, arg_num)) {
3825 /* For IS_VAR operands, SEND_VAL will pass through the operand without
3826 * dereferencing, so it will use a by-ref pass if the call returned by-ref
3827 * and a by-value pass if it returned by-value. */
3828 opcode = ZEND_SEND_VAL;
3829 } else {
3830 opcode = ZEND_SEND_VAR;
3831 }
3832 } else {
3833 opcode = ZEND_SEND_VAR_NO_REF_EX;
3834 }
3835 }
3836 } else if (zend_is_variable(arg) && !zend_ast_is_short_circuited(arg)) {
3837 if (fbc && arg_num != (uint32_t) -1) {
3838 if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
3839 zend_compile_var(&arg_node, arg, BP_VAR_W, 1);
3840 opcode = ZEND_SEND_REF;
3841 } else {
3842 zend_compile_var(&arg_node, arg, BP_VAR_R, 0);
3843 opcode = (arg_node.op_type == IS_TMP_VAR) ? ZEND_SEND_VAL : ZEND_SEND_VAR;
3844 }
3845 } else {
3846 do {
3847 if (arg->kind == ZEND_AST_VAR) {
3848 CG(zend_lineno) = zend_ast_get_lineno(ast);
3849 if (is_this_fetch(arg)) {
3850 zend_emit_op(&arg_node, ZEND_FETCH_THIS, NULL, NULL);
3851 opcode = ZEND_SEND_VAR_EX;
3852 CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
3853 break;
3854 } else if (zend_try_compile_cv(&arg_node, arg) == SUCCESS) {
3855 opcode = ZEND_SEND_VAR_EX;
3856 break;
3857 }
3858 }
3859 opline = zend_emit_op(NULL, ZEND_CHECK_FUNC_ARG, NULL, NULL);
3860 if (arg_name) {
3861 opline->op2_type = IS_CONST;
3862 zend_string_addref(arg_name);
3863 opline->op2.constant = zend_add_literal_string(&arg_name);
3864 opline->result.num = zend_alloc_cache_slots(2);
3865 } else {
3866 opline->op2.num = arg_num;
3867 }
3868 zend_compile_var(&arg_node, arg, BP_VAR_FUNC_ARG, 1);
3869 opcode = ZEND_SEND_FUNC_ARG;
3870 } while (0);
3871 }
3872 } else {
3873 zend_compile_expr(&arg_node, arg);
3874 if (arg_node.op_type == IS_VAR) {
3875 /* pass ++$a or something similar */
3876 if (fbc && arg_num != (uint32_t) -1) {
3877 if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
3878 opcode = ZEND_SEND_VAR_NO_REF;
3879 } else if (ARG_MAY_BE_SENT_BY_REF(fbc, arg_num)) {
3880 opcode = ZEND_SEND_VAL;
3881 } else {
3882 opcode = ZEND_SEND_VAR;
3883 }
3884 } else {
3885 opcode = ZEND_SEND_VAR_NO_REF_EX;
3886 }
3887 } else if (arg_node.op_type == IS_CV) {
3888 if (fbc && arg_num != (uint32_t) -1) {
3889 if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
3890 opcode = ZEND_SEND_REF;
3891 } else {
3892 opcode = ZEND_SEND_VAR;
3893 }
3894 } else {
3895 opcode = ZEND_SEND_VAR_EX;
3896 }
3897 } else {
3898 /* Delay "Only variables can be passed by reference" error to execution */
3899 if (fbc && arg_num != (uint32_t) -1 && !ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
3900 opcode = ZEND_SEND_VAL;
3901 } else {
3902 opcode = ZEND_SEND_VAL_EX;
3903 }
3904 }
3905 }
3906
3907 opline = zend_emit_op(NULL, opcode, &arg_node, NULL);
3908 if (arg_name) {
3909 opline->op2_type = IS_CONST;
3910 zend_string_addref(arg_name);
3911 opline->op2.constant = zend_add_literal_string(&arg_name);
3912 opline->result.num = zend_alloc_cache_slots(2);
3913 } else {
3914 opline->op2.opline_num = arg_num;
3915 opline->result.var = EX_NUM_TO_VAR(arg_num - 1);
3916 }
3917 }
3918
3919 if (may_have_undef) {
3920 zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL);
3921 }
3922
3923 return arg_count;
3924 }
3925 /* }}} */
3926
zend_get_call_op(const zend_op * init_op,zend_function * fbc)3927 ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* {{{ */
3928 {
3929 if (fbc) {
3930 ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE));
3931 if (fbc->type == ZEND_INTERNAL_FUNCTION && !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) {
3932 if (init_op->opcode == ZEND_INIT_FCALL && !zend_execute_internal) {
3933 if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) {
3934 return ZEND_DO_ICALL;
3935 } else {
3936 return ZEND_DO_FCALL_BY_NAME;
3937 }
3938 }
3939 } else if (!(CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)){
3940 if (zend_execute_ex == execute_ex) {
3941 if (!(fbc->common.fn_flags & ZEND_ACC_DEPRECATED)) {
3942 return ZEND_DO_UCALL;
3943 } else {
3944 return ZEND_DO_FCALL_BY_NAME;
3945 }
3946 }
3947 }
3948 } else if (zend_execute_ex == execute_ex &&
3949 !zend_execute_internal &&
3950 (init_op->opcode == ZEND_INIT_FCALL_BY_NAME ||
3951 init_op->opcode == ZEND_INIT_NS_FCALL_BY_NAME)) {
3952 return ZEND_DO_FCALL_BY_NAME;
3953 }
3954 return ZEND_DO_FCALL;
3955 }
3956 /* }}} */
3957
zend_compile_call_common(znode * result,zend_ast * args_ast,zend_function * fbc,uint32_t lineno)3958 static bool zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc, uint32_t lineno) /* {{{ */
3959 {
3960 zend_op *opline;
3961 uint32_t opnum_init = get_next_op_number() - 1;
3962
3963 if (args_ast->kind == ZEND_AST_CALLABLE_CONVERT) {
3964 opline = &CG(active_op_array)->opcodes[opnum_init];
3965 opline->extended_value = 0;
3966
3967 if (opline->opcode == ZEND_NEW) {
3968 zend_error_noreturn(E_COMPILE_ERROR, "Cannot create Closure for new expression");
3969 }
3970
3971 if (opline->opcode == ZEND_INIT_FCALL) {
3972 opline->op1.num = zend_vm_calc_used_stack(0, fbc);
3973 }
3974
3975 zend_emit_op_tmp(result, ZEND_CALLABLE_CONVERT, NULL, NULL);
3976 return true;
3977 }
3978
3979 bool may_have_extra_named_args;
3980 uint32_t arg_count = zend_compile_args(args_ast, fbc, &may_have_extra_named_args);
3981
3982 zend_do_extended_fcall_begin();
3983
3984 opline = &CG(active_op_array)->opcodes[opnum_init];
3985 opline->extended_value = arg_count;
3986
3987 if (opline->opcode == ZEND_INIT_FCALL) {
3988 opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc);
3989 }
3990
3991 opline = zend_emit_op(result, zend_get_call_op(opline, fbc), NULL, NULL);
3992 if (may_have_extra_named_args) {
3993 opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
3994 }
3995 opline->lineno = lineno;
3996 zend_do_extended_fcall_end();
3997 return false;
3998 }
3999 /* }}} */
4000
zend_compile_function_name(znode * name_node,zend_ast * name_ast)4001 static bool zend_compile_function_name(znode *name_node, zend_ast *name_ast) /* {{{ */
4002 {
4003 zend_string *orig_name = zend_ast_get_str(name_ast);
4004 bool is_fully_qualified;
4005
4006 name_node->op_type = IS_CONST;
4007 ZVAL_STR(&name_node->u.constant, zend_resolve_function_name(
4008 orig_name, name_ast->attr, &is_fully_qualified));
4009
4010 return !is_fully_qualified && FC(current_namespace);
4011 }
4012 /* }}} */
4013
zend_compile_dynamic_call(znode * result,znode * name_node,zend_ast * args_ast,uint32_t lineno)4014 static void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast, uint32_t lineno) /* {{{ */
4015 {
4016 if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) {
4017 const char *colon;
4018 zend_string *str = Z_STR(name_node->u.constant);
4019 if ((colon = zend_memrchr(ZSTR_VAL(str), ':', ZSTR_LEN(str))) != NULL && colon > ZSTR_VAL(str) && *(colon - 1) == ':') {
4020 zend_string *class = zend_string_init(ZSTR_VAL(str), colon - ZSTR_VAL(str) - 1, 0);
4021 zend_string *method = zend_string_init(colon + 1, ZSTR_LEN(str) - (colon - ZSTR_VAL(str)) - 1, 0);
4022 zend_op *opline = get_next_op();
4023
4024 opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
4025 opline->op1_type = IS_CONST;
4026 opline->op1.constant = zend_add_class_name_literal(class);
4027 opline->op2_type = IS_CONST;
4028 opline->op2.constant = zend_add_func_name_literal(method);
4029 /* 2 slots, for class and method */
4030 opline->result.num = zend_alloc_cache_slots(2);
4031 zval_ptr_dtor(&name_node->u.constant);
4032 } else {
4033 zend_op *opline = get_next_op();
4034
4035 opline->opcode = ZEND_INIT_FCALL_BY_NAME;
4036 opline->op2_type = IS_CONST;
4037 opline->op2.constant = zend_add_func_name_literal(str);
4038 opline->result.num = zend_alloc_cache_slot();
4039 }
4040 } else {
4041 zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node);
4042 }
4043
4044 zend_compile_call_common(result, args_ast, NULL, lineno);
4045 }
4046 /* }}} */
4047
zend_args_contain_unpack_or_named(zend_ast_list * args)4048 static inline bool zend_args_contain_unpack_or_named(zend_ast_list *args) /* {{{ */
4049 {
4050 uint32_t i;
4051 for (i = 0; i < args->children; ++i) {
4052 zend_ast *arg = args->child[i];
4053 if (arg->kind == ZEND_AST_UNPACK || arg->kind == ZEND_AST_NAMED_ARG) {
4054 return 1;
4055 }
4056 }
4057 return 0;
4058 }
4059 /* }}} */
4060
zend_compile_func_strlen(znode * result,zend_ast_list * args)4061 static zend_result zend_compile_func_strlen(znode *result, zend_ast_list *args) /* {{{ */
4062 {
4063 znode arg_node;
4064
4065 if (args->children != 1) {
4066 return FAILURE;
4067 }
4068
4069 zend_compile_expr(&arg_node, args->child[0]);
4070 if (arg_node.op_type == IS_CONST && Z_TYPE(arg_node.u.constant) == IS_STRING) {
4071 result->op_type = IS_CONST;
4072 ZVAL_LONG(&result->u.constant, Z_STRLEN(arg_node.u.constant));
4073 zval_ptr_dtor_str(&arg_node.u.constant);
4074 } else {
4075 zend_emit_op_tmp(result, ZEND_STRLEN, &arg_node, NULL);
4076 }
4077 return SUCCESS;
4078 }
4079 /* }}} */
4080
zend_compile_func_typecheck(znode * result,zend_ast_list * args,uint32_t type)4081 static zend_result zend_compile_func_typecheck(znode *result, zend_ast_list *args, uint32_t type) /* {{{ */
4082 {
4083 znode arg_node;
4084 zend_op *opline;
4085
4086 if (args->children != 1) {
4087 return FAILURE;
4088 }
4089
4090 zend_compile_expr(&arg_node, args->child[0]);
4091 opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL);
4092 if (type != _IS_BOOL) {
4093 opline->extended_value = (1 << type);
4094 } else {
4095 opline->extended_value = (1 << IS_FALSE) | (1 << IS_TRUE);
4096 }
4097 return SUCCESS;
4098 }
4099 /* }}} */
4100
zend_compile_func_is_scalar(znode * result,zend_ast_list * args)4101 static zend_result zend_compile_func_is_scalar(znode *result, zend_ast_list *args) /* {{{ */
4102 {
4103 znode arg_node;
4104 zend_op *opline;
4105
4106 if (args->children != 1) {
4107 return FAILURE;
4108 }
4109
4110 zend_compile_expr(&arg_node, args->child[0]);
4111 opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL);
4112 opline->extended_value = (1 << IS_FALSE | 1 << IS_TRUE | 1 << IS_DOUBLE | 1 << IS_LONG | 1 << IS_STRING);
4113 return SUCCESS;
4114 }
4115
zend_compile_func_cast(znode * result,zend_ast_list * args,uint32_t type)4116 static zend_result zend_compile_func_cast(znode *result, zend_ast_list *args, uint32_t type) /* {{{ */
4117 {
4118 znode arg_node;
4119 zend_op *opline;
4120
4121 if (args->children != 1) {
4122 return FAILURE;
4123 }
4124
4125 zend_compile_expr(&arg_node, args->child[0]);
4126 if (type == _IS_BOOL) {
4127 opline = zend_emit_op_tmp(result, ZEND_BOOL, &arg_node, NULL);
4128 } else {
4129 opline = zend_emit_op_tmp(result, ZEND_CAST, &arg_node, NULL);
4130 opline->extended_value = type;
4131 }
4132 return SUCCESS;
4133 }
4134 /* }}} */
4135
zend_compile_func_defined(znode * result,zend_ast_list * args)4136 static zend_result zend_compile_func_defined(znode *result, zend_ast_list *args) /* {{{ */
4137 {
4138 zend_string *name;
4139 zend_op *opline;
4140
4141 if (args->children != 1 || args->child[0]->kind != ZEND_AST_ZVAL) {
4142 return FAILURE;
4143 }
4144
4145 name = zval_get_string(zend_ast_get_zval(args->child[0]));
4146 if (zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)) || zend_memrchr(ZSTR_VAL(name), ':', ZSTR_LEN(name))) {
4147 zend_string_release_ex(name, 0);
4148 return FAILURE;
4149 }
4150
4151 if (zend_try_ct_eval_const(&result->u.constant, name, 0)) {
4152 zend_string_release_ex(name, 0);
4153 zval_ptr_dtor(&result->u.constant);
4154 ZVAL_TRUE(&result->u.constant);
4155 result->op_type = IS_CONST;
4156 return SUCCESS;
4157 }
4158
4159 opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL);
4160 opline->op1_type = IS_CONST;
4161 LITERAL_STR(opline->op1, name);
4162 opline->extended_value = zend_alloc_cache_slot();
4163
4164 return SUCCESS;
4165 }
4166 /* }}} */
4167
zend_compile_func_chr(znode * result,zend_ast_list * args)4168 static zend_result zend_compile_func_chr(znode *result, zend_ast_list *args) /* {{{ */
4169 {
4170
4171 if (args->children == 1 &&
4172 args->child[0]->kind == ZEND_AST_ZVAL &&
4173 Z_TYPE_P(zend_ast_get_zval(args->child[0])) == IS_LONG) {
4174
4175 zend_long c = Z_LVAL_P(zend_ast_get_zval(args->child[0])) & 0xff;
4176
4177 result->op_type = IS_CONST;
4178 ZVAL_CHAR(&result->u.constant, c);
4179 return SUCCESS;
4180 } else {
4181 return FAILURE;
4182 }
4183 }
4184 /* }}} */
4185
zend_compile_func_ord(znode * result,zend_ast_list * args)4186 static zend_result zend_compile_func_ord(znode *result, zend_ast_list *args) /* {{{ */
4187 {
4188 if (args->children == 1 &&
4189 args->child[0]->kind == ZEND_AST_ZVAL &&
4190 Z_TYPE_P(zend_ast_get_zval(args->child[0])) == IS_STRING) {
4191
4192 result->op_type = IS_CONST;
4193 ZVAL_LONG(&result->u.constant, (unsigned char)Z_STRVAL_P(zend_ast_get_zval(args->child[0]))[0]);
4194 return SUCCESS;
4195 } else {
4196 return FAILURE;
4197 }
4198 }
4199 /* }}} */
4200
4201 /* We can only calculate the stack size for functions that have been fully compiled, otherwise
4202 * additional CV or TMP slots may still be added. This prevents the use of INIT_FCALL for
4203 * directly or indirectly recursive function calls. */
fbc_is_finalized(zend_function * fbc)4204 static bool fbc_is_finalized(zend_function *fbc) {
4205 return !ZEND_USER_CODE(fbc->type) || (fbc->common.fn_flags & ZEND_ACC_DONE_PASS_TWO);
4206 }
4207
zend_compile_ignore_class(zend_class_entry * ce,zend_string * filename)4208 static bool zend_compile_ignore_class(zend_class_entry *ce, zend_string *filename)
4209 {
4210 if (ce->type == ZEND_INTERNAL_CLASS) {
4211 return CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
4212 } else {
4213 return (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
4214 && ce->info.user.filename != filename;
4215 }
4216 }
4217
zend_compile_ignore_function(zend_function * fbc,zend_string * filename)4218 static bool zend_compile_ignore_function(zend_function *fbc, zend_string *filename)
4219 {
4220 if (fbc->type == ZEND_INTERNAL_FUNCTION) {
4221 return CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS;
4222 } else {
4223 return (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)
4224 || ((CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
4225 && fbc->op_array.filename != filename);
4226 }
4227 }
4228
zend_try_compile_ct_bound_init_user_func(zend_ast * name_ast,uint32_t num_args)4229 static zend_result zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t num_args) /* {{{ */
4230 {
4231 zend_string *name, *lcname;
4232 zend_function *fbc;
4233 zend_op *opline;
4234
4235 if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
4236 return FAILURE;
4237 }
4238
4239 name = zend_ast_get_str(name_ast);
4240 lcname = zend_string_tolower(name);
4241
4242 fbc = zend_hash_find_ptr(CG(function_table), lcname);
4243 if (!fbc
4244 || !fbc_is_finalized(fbc)
4245 || zend_compile_ignore_function(fbc, CG(active_op_array)->filename)) {
4246 zend_string_release_ex(lcname, 0);
4247 return FAILURE;
4248 }
4249
4250 opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, NULL);
4251 opline->extended_value = num_args;
4252 opline->op1.num = zend_vm_calc_used_stack(num_args, fbc);
4253 opline->op2_type = IS_CONST;
4254 LITERAL_STR(opline->op2, lcname);
4255 opline->result.num = zend_alloc_cache_slot();
4256
4257 return SUCCESS;
4258 }
4259 /* }}} */
4260
zend_compile_init_user_func(zend_ast * name_ast,uint32_t num_args,zend_string * orig_func_name)4261 static void zend_compile_init_user_func(zend_ast *name_ast, uint32_t num_args, zend_string *orig_func_name) /* {{{ */
4262 {
4263 zend_op *opline;
4264 znode name_node;
4265
4266 if (zend_try_compile_ct_bound_init_user_func(name_ast, num_args) == SUCCESS) {
4267 return;
4268 }
4269
4270 zend_compile_expr(&name_node, name_ast);
4271
4272 opline = zend_emit_op(NULL, ZEND_INIT_USER_CALL, NULL, &name_node);
4273 opline->op1_type = IS_CONST;
4274 LITERAL_STR(opline->op1, zend_string_copy(orig_func_name));
4275 opline->extended_value = num_args;
4276 }
4277 /* }}} */
4278
4279 /* cufa = call_user_func_array */
zend_compile_func_cufa(znode * result,zend_ast_list * args,zend_string * lcname)4280 static zend_result zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */
4281 {
4282 znode arg_node;
4283 zend_op *opline;
4284
4285 if (args->children != 2) {
4286 return FAILURE;
4287 }
4288
4289 zend_compile_init_user_func(args->child[0], 0, lcname);
4290 if (args->child[1]->kind == ZEND_AST_CALL
4291 && args->child[1]->child[0]->kind == ZEND_AST_ZVAL
4292 && Z_TYPE_P(zend_ast_get_zval(args->child[1]->child[0])) == IS_STRING
4293 && args->child[1]->child[1]->kind == ZEND_AST_ARG_LIST) {
4294 zend_string *orig_name = zend_ast_get_str(args->child[1]->child[0]);
4295 zend_ast_list *list = zend_ast_get_list(args->child[1]->child[1]);
4296 bool is_fully_qualified;
4297 zend_string *name = zend_resolve_function_name(orig_name, args->child[1]->child[0]->attr, &is_fully_qualified);
4298
4299 if (zend_string_equals_literal_ci(name, "array_slice")
4300 && !zend_args_contain_unpack_or_named(list)
4301 && list->children == 3
4302 && list->child[1]->kind == ZEND_AST_ZVAL) {
4303 zval *zv = zend_ast_get_zval(list->child[1]);
4304
4305 if (Z_TYPE_P(zv) == IS_LONG
4306 && Z_LVAL_P(zv) >= 0
4307 && Z_LVAL_P(zv) <= 0x7fffffff) {
4308 zend_op *opline;
4309 znode len_node;
4310
4311 zend_compile_expr(&arg_node, list->child[0]);
4312 zend_compile_expr(&len_node, list->child[2]);
4313 opline = zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, &len_node);
4314 opline->extended_value = Z_LVAL_P(zv);
4315 zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
4316 zend_string_release_ex(name, 0);
4317 return SUCCESS;
4318 }
4319 }
4320 zend_string_release_ex(name, 0);
4321 }
4322 zend_compile_expr(&arg_node, args->child[1]);
4323 zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL);
4324 zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL);
4325 opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
4326 opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
4327
4328 return SUCCESS;
4329 }
4330 /* }}} */
4331
4332 /* cuf = call_user_func */
zend_compile_func_cuf(znode * result,zend_ast_list * args,zend_string * lcname)4333 static zend_result zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */
4334 {
4335 uint32_t i;
4336
4337 if (args->children < 1) {
4338 return FAILURE;
4339 }
4340
4341 zend_compile_init_user_func(args->child[0], args->children - 1, lcname);
4342 for (i = 1; i < args->children; ++i) {
4343 zend_ast *arg_ast = args->child[i];
4344 znode arg_node;
4345 zend_op *opline;
4346
4347 zend_compile_expr(&arg_node, arg_ast);
4348
4349 opline = zend_emit_op(NULL, ZEND_SEND_USER, &arg_node, NULL);
4350 opline->op2.num = i;
4351 opline->result.var = EX_NUM_TO_VAR(i - 1);
4352 }
4353 zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
4354
4355 return SUCCESS;
4356 }
4357 /* }}} */
4358
zend_compile_assert(znode * result,zend_ast_list * args,zend_string * name,zend_function * fbc,uint32_t lineno)4359 static void zend_compile_assert(znode *result, zend_ast_list *args, zend_string *name, zend_function *fbc, uint32_t lineno) /* {{{ */
4360 {
4361 if (EG(assertions) >= 0) {
4362 znode name_node;
4363 zend_op *opline;
4364 uint32_t check_op_number = get_next_op_number();
4365
4366 zend_emit_op(NULL, ZEND_ASSERT_CHECK, NULL, NULL);
4367
4368 if (fbc && fbc_is_finalized(fbc)) {
4369 name_node.op_type = IS_CONST;
4370 ZVAL_STR_COPY(&name_node.u.constant, name);
4371
4372 opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node);
4373 } else {
4374 opline = zend_emit_op(NULL, ZEND_INIT_NS_FCALL_BY_NAME, NULL, NULL);
4375 opline->op2_type = IS_CONST;
4376 opline->op2.constant = zend_add_ns_func_name_literal(name);
4377 }
4378 opline->result.num = zend_alloc_cache_slot();
4379
4380 if (args->children == 1) {
4381 /* add "assert(condition) as assertion message */
4382 zend_ast *arg = zend_ast_create_zval_from_str(
4383 zend_ast_export("assert(", args->child[0], ")"));
4384 if (args->child[0]->kind == ZEND_AST_NAMED_ARG) {
4385 /* If the original argument was named, add the new argument as named as well,
4386 * as mixing named and positional is not allowed. */
4387 zend_ast *name = zend_ast_create_zval_from_str(
4388 ZSTR_INIT_LITERAL("description", 0));
4389 arg = zend_ast_create(ZEND_AST_NAMED_ARG, name, arg);
4390 }
4391 zend_ast_list_add((zend_ast *) args, arg);
4392 }
4393
4394 zend_compile_call_common(result, (zend_ast*)args, fbc, lineno);
4395
4396 opline = &CG(active_op_array)->opcodes[check_op_number];
4397 opline->op2.opline_num = get_next_op_number();
4398 SET_NODE(opline->result, result);
4399 } else {
4400 if (!fbc) {
4401 zend_string_release_ex(name, 0);
4402 }
4403 result->op_type = IS_CONST;
4404 ZVAL_TRUE(&result->u.constant);
4405 }
4406 }
4407 /* }}} */
4408
zend_compile_func_in_array(znode * result,zend_ast_list * args)4409 static zend_result zend_compile_func_in_array(znode *result, zend_ast_list *args) /* {{{ */
4410 {
4411 bool strict = 0;
4412 znode array, needly;
4413 zend_op *opline;
4414
4415 if (args->children == 3) {
4416 if (args->child[2]->kind == ZEND_AST_ZVAL) {
4417 strict = zend_is_true(zend_ast_get_zval(args->child[2]));
4418 } else if (args->child[2]->kind == ZEND_AST_CONST) {
4419 zval value;
4420 zend_ast *name_ast = args->child[2]->child[0];
4421 bool is_fully_qualified;
4422 zend_string *resolved_name = zend_resolve_const_name(
4423 zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified);
4424
4425 if (!zend_try_ct_eval_const(&value, resolved_name, is_fully_qualified)) {
4426 zend_string_release_ex(resolved_name, 0);
4427 return FAILURE;
4428 }
4429
4430 zend_string_release_ex(resolved_name, 0);
4431 strict = zend_is_true(&value);
4432 zval_ptr_dtor(&value);
4433 } else {
4434 return FAILURE;
4435 }
4436 } else if (args->children != 2) {
4437 return FAILURE;
4438 }
4439
4440 if (args->child[1]->kind != ZEND_AST_ARRAY
4441 || !zend_try_ct_eval_array(&array.u.constant, args->child[1])) {
4442 return FAILURE;
4443 }
4444
4445 if (zend_hash_num_elements(Z_ARRVAL(array.u.constant)) > 0) {
4446 bool ok = 1;
4447 zval *val, tmp;
4448 HashTable *src = Z_ARRVAL(array.u.constant);
4449 HashTable *dst = zend_new_array(zend_hash_num_elements(src));
4450
4451 ZVAL_TRUE(&tmp);
4452
4453 if (strict) {
4454 ZEND_HASH_FOREACH_VAL(src, val) {
4455 if (Z_TYPE_P(val) == IS_STRING) {
4456 zend_hash_add(dst, Z_STR_P(val), &tmp);
4457 } else if (Z_TYPE_P(val) == IS_LONG) {
4458 zend_hash_index_add(dst, Z_LVAL_P(val), &tmp);
4459 } else {
4460 zend_array_destroy(dst);
4461 ok = 0;
4462 break;
4463 }
4464 } ZEND_HASH_FOREACH_END();
4465 } else {
4466 ZEND_HASH_FOREACH_VAL(src, val) {
4467 if (Z_TYPE_P(val) != IS_STRING
4468 || is_numeric_string(Z_STRVAL_P(val), Z_STRLEN_P(val), NULL, NULL, 0)) {
4469 zend_array_destroy(dst);
4470 ok = 0;
4471 break;
4472 }
4473 zend_hash_add(dst, Z_STR_P(val), &tmp);
4474 } ZEND_HASH_FOREACH_END();
4475 }
4476
4477 zend_array_destroy(src);
4478 if (!ok) {
4479 return FAILURE;
4480 }
4481 Z_ARRVAL(array.u.constant) = dst;
4482 }
4483 array.op_type = IS_CONST;
4484
4485 zend_compile_expr(&needly, args->child[0]);
4486
4487 opline = zend_emit_op_tmp(result, ZEND_IN_ARRAY, &needly, &array);
4488 opline->extended_value = strict;
4489
4490 return SUCCESS;
4491 }
4492 /* }}} */
4493
zend_compile_func_count(znode * result,zend_ast_list * args,zend_string * lcname)4494 static zend_result zend_compile_func_count(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */
4495 {
4496 znode arg_node;
4497 zend_op *opline;
4498
4499 if (args->children != 1) {
4500 return FAILURE;
4501 }
4502
4503 zend_compile_expr(&arg_node, args->child[0]);
4504 opline = zend_emit_op_tmp(result, ZEND_COUNT, &arg_node, NULL);
4505 opline->extended_value = zend_string_equals_literal(lcname, "sizeof");
4506
4507 return SUCCESS;
4508 }
4509 /* }}} */
4510
zend_compile_func_get_class(znode * result,zend_ast_list * args)4511 static zend_result zend_compile_func_get_class(znode *result, zend_ast_list *args) /* {{{ */
4512 {
4513 if (args->children == 0) {
4514 zend_emit_op_tmp(result, ZEND_GET_CLASS, NULL, NULL);
4515 } else {
4516 znode arg_node;
4517
4518 if (args->children != 1) {
4519 return FAILURE;
4520 }
4521
4522 zend_compile_expr(&arg_node, args->child[0]);
4523 zend_emit_op_tmp(result, ZEND_GET_CLASS, &arg_node, NULL);
4524 }
4525 return SUCCESS;
4526 }
4527 /* }}} */
4528
zend_compile_func_get_called_class(znode * result,zend_ast_list * args)4529 static zend_result zend_compile_func_get_called_class(znode *result, zend_ast_list *args) /* {{{ */
4530 {
4531 if (args->children != 0) {
4532 return FAILURE;
4533 }
4534
4535 zend_emit_op_tmp(result, ZEND_GET_CALLED_CLASS, NULL, NULL);
4536 return SUCCESS;
4537 }
4538 /* }}} */
4539
zend_compile_func_gettype(znode * result,zend_ast_list * args)4540 static zend_result zend_compile_func_gettype(znode *result, zend_ast_list *args) /* {{{ */
4541 {
4542 znode arg_node;
4543
4544 if (args->children != 1) {
4545 return FAILURE;
4546 }
4547
4548 zend_compile_expr(&arg_node, args->child[0]);
4549 zend_emit_op_tmp(result, ZEND_GET_TYPE, &arg_node, NULL);
4550 return SUCCESS;
4551 }
4552 /* }}} */
4553
zend_compile_func_num_args(znode * result,zend_ast_list * args)4554 static zend_result zend_compile_func_num_args(znode *result, zend_ast_list *args) /* {{{ */
4555 {
4556 if (CG(active_op_array)->function_name && args->children == 0) {
4557 zend_emit_op_tmp(result, ZEND_FUNC_NUM_ARGS, NULL, NULL);
4558 return SUCCESS;
4559 } else {
4560 return FAILURE;
4561 }
4562 }
4563 /* }}} */
4564
zend_compile_func_get_args(znode * result,zend_ast_list * args)4565 static zend_result zend_compile_func_get_args(znode *result, zend_ast_list *args) /* {{{ */
4566 {
4567 if (CG(active_op_array)->function_name && args->children == 0) {
4568 zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, NULL, NULL);
4569 return SUCCESS;
4570 } else {
4571 return FAILURE;
4572 }
4573 }
4574 /* }}} */
4575
zend_compile_func_array_key_exists(znode * result,zend_ast_list * args)4576 static zend_result zend_compile_func_array_key_exists(znode *result, zend_ast_list *args) /* {{{ */
4577 {
4578 znode subject, needle;
4579
4580 if (args->children != 2) {
4581 return FAILURE;
4582 }
4583
4584 zend_compile_expr(&needle, args->child[0]);
4585 zend_compile_expr(&subject, args->child[1]);
4586
4587 zend_emit_op_tmp(result, ZEND_ARRAY_KEY_EXISTS, &needle, &subject);
4588 return SUCCESS;
4589 }
4590 /* }}} */
4591
zend_compile_func_array_slice(znode * result,zend_ast_list * args)4592 static zend_result zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */
4593 {
4594 if (CG(active_op_array)->function_name
4595 && args->children == 2
4596 && args->child[0]->kind == ZEND_AST_CALL
4597 && args->child[0]->child[0]->kind == ZEND_AST_ZVAL
4598 && Z_TYPE_P(zend_ast_get_zval(args->child[0]->child[0])) == IS_STRING
4599 && args->child[0]->child[1]->kind == ZEND_AST_ARG_LIST
4600 && args->child[1]->kind == ZEND_AST_ZVAL) {
4601
4602 zend_string *orig_name = zend_ast_get_str(args->child[0]->child[0]);
4603 bool is_fully_qualified;
4604 zend_string *name = zend_resolve_function_name(orig_name, args->child[0]->child[0]->attr, &is_fully_qualified);
4605 zend_ast_list *list = zend_ast_get_list(args->child[0]->child[1]);
4606 zval *zv = zend_ast_get_zval(args->child[1]);
4607 znode first;
4608
4609 if (zend_string_equals_literal_ci(name, "func_get_args")
4610 && list->children == 0
4611 && Z_TYPE_P(zv) == IS_LONG
4612 && Z_LVAL_P(zv) >= 0) {
4613 first.op_type = IS_CONST;
4614 ZVAL_LONG(&first.u.constant, Z_LVAL_P(zv));
4615 zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, &first, NULL);
4616 zend_string_release_ex(name, 0);
4617 return SUCCESS;
4618 }
4619 zend_string_release_ex(name, 0);
4620 }
4621 return FAILURE;
4622 }
4623 /* }}} */
4624
find_frameless_function_offset(uint32_t arity,void * handler)4625 static uint32_t find_frameless_function_offset(uint32_t arity, void *handler)
4626 {
4627 void **handlers = zend_flf_handlers;
4628 void **current = handlers;
4629 while (current) {
4630 if (*current == handler) {
4631 return current - handlers;
4632 }
4633 current++;
4634 }
4635
4636 return (uint32_t)-1;
4637 }
4638
find_frameless_function_info(zend_ast_list * args,zend_function * fbc,uint32_t type)4639 static const zend_frameless_function_info *find_frameless_function_info(zend_ast_list *args, zend_function *fbc, uint32_t type)
4640 {
4641 if (zend_execute_internal) {
4642 return NULL;
4643 }
4644
4645 if (type != BP_VAR_R) {
4646 return NULL;
4647 }
4648
4649 if (ZEND_USER_CODE(fbc->type)) {
4650 return NULL;
4651 }
4652
4653 const zend_frameless_function_info *frameless_function_info = fbc->internal_function.frameless_function_infos;
4654 if (!frameless_function_info) {
4655 return NULL;
4656 }
4657
4658 if (args->children > 3) {
4659 return NULL;
4660 }
4661
4662 while (frameless_function_info->handler) {
4663 if (frameless_function_info->num_args >= args->children
4664 && fbc->common.required_num_args <= args->children
4665 && (!(fbc->common.fn_flags & ZEND_ACC_VARIADIC)
4666 || frameless_function_info->num_args == args->children)) {
4667 uint32_t num_args = frameless_function_info->num_args;
4668 uint32_t offset = find_frameless_function_offset(num_args, frameless_function_info->handler);
4669 if (offset == (uint32_t)-1) {
4670 continue;
4671 }
4672 return frameless_function_info;
4673 }
4674 frameless_function_info++;
4675 }
4676
4677 return NULL;
4678 }
4679
zend_compile_frameless_icall_ex(znode * result,zend_ast_list * args,zend_function * fbc,const zend_frameless_function_info * frameless_function_info,uint32_t type)4680 static uint32_t zend_compile_frameless_icall_ex(znode *result, zend_ast_list *args, zend_function *fbc, const zend_frameless_function_info *frameless_function_info, uint32_t type)
4681 {
4682 int lineno = CG(zend_lineno);
4683 uint32_t num_args = frameless_function_info->num_args;
4684 uint32_t offset = find_frameless_function_offset(num_args, frameless_function_info->handler);
4685 znode arg_zvs[3];
4686 for (uint32_t i = 0; i < num_args; i++) {
4687 if (i < args->children) {
4688 zend_compile_expr(&arg_zvs[i], args->child[i]);
4689 } else {
4690 zend_internal_arg_info *arg_info = (zend_internal_arg_info *)&fbc->common.arg_info[i];
4691 arg_zvs[i].op_type = IS_CONST;
4692 if (zend_get_default_from_internal_arg_info(&arg_zvs[i].u.constant, arg_info) == FAILURE) {
4693 ZEND_UNREACHABLE();
4694 }
4695 }
4696 }
4697 uint8_t opcode = ZEND_FRAMELESS_ICALL_0 + num_args;
4698 uint32_t opnum = get_next_op_number();
4699 zend_op *opline = zend_emit_op_tmp(result, opcode, NULL, NULL);
4700 opline->extended_value = offset;
4701 opline->lineno = lineno;
4702 if (num_args >= 1) {
4703 SET_NODE(opline->op1, &arg_zvs[0]);
4704 }
4705 if (num_args >= 2) {
4706 SET_NODE(opline->op2, &arg_zvs[1]);
4707 }
4708 if (num_args >= 3) {
4709 zend_emit_op_data(&arg_zvs[2]);
4710 }
4711 return opnum;
4712 }
4713
zend_compile_frameless_icall(znode * result,zend_ast_list * args,zend_function * fbc,uint32_t type)4714 static uint32_t zend_compile_frameless_icall(znode *result, zend_ast_list *args, zend_function *fbc, uint32_t type)
4715 {
4716 const zend_frameless_function_info *frameless_function_info = find_frameless_function_info(args, fbc, type);
4717 if (!frameless_function_info) {
4718 return (uint32_t)-1;
4719 }
4720
4721 return zend_compile_frameless_icall_ex(result, args, fbc, frameless_function_info, type);
4722 }
4723
zend_compile_ns_call(znode * result,znode * name_node,zend_ast * args_ast,uint32_t lineno,uint32_t type)4724 static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast, uint32_t lineno, uint32_t type) /* {{{ */
4725 {
4726 int name_constants = zend_add_ns_func_name_literal(Z_STR(name_node->u.constant));
4727
4728 /* Find frameless function with same name. */
4729 zend_function *frameless_function = NULL;
4730 if (args_ast->kind != ZEND_AST_CALLABLE_CONVERT
4731 && !zend_args_contain_unpack_or_named(zend_ast_get_list(args_ast))
4732 /* Avoid blowing up op count with nested frameless branches. */
4733 && !CG(context).in_jmp_frameless_branch) {
4734 zend_string *lc_func_name = Z_STR_P(CT_CONSTANT_EX(CG(active_op_array), name_constants + 2));
4735 frameless_function = zend_hash_find_ptr(CG(function_table), lc_func_name);
4736 }
4737
4738 /* Check whether any frameless handler may actually be used. */
4739 uint32_t jmp_fl_opnum = 0;
4740 const zend_frameless_function_info *frameless_function_info = NULL;
4741 if (frameless_function) {
4742 frameless_function_info = find_frameless_function_info(zend_ast_get_list(args_ast), frameless_function, type);
4743 if (frameless_function_info) {
4744 CG(context).in_jmp_frameless_branch = true;
4745 znode op1;
4746 op1.op_type = IS_CONST;
4747 ZVAL_COPY(&op1.u.constant, CT_CONSTANT_EX(CG(active_op_array), name_constants + 1));
4748 jmp_fl_opnum = get_next_op_number();
4749 zend_emit_op(NULL, ZEND_JMP_FRAMELESS, &op1, NULL);
4750 }
4751 }
4752
4753 /* Compile ns call. */
4754 zend_op *opline = get_next_op();
4755 opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
4756 opline->op2_type = IS_CONST;
4757 opline->op2.constant = name_constants;
4758 opline->result.num = zend_alloc_cache_slot();
4759 zend_compile_call_common(result, args_ast, NULL, lineno);
4760
4761 /* Compile frameless call. */
4762 if (frameless_function_info) {
4763 CG(zend_lineno) = lineno;
4764
4765 uint32_t jmp_end_opnum = zend_emit_jump(0);
4766 uint32_t jmp_fl_target = get_next_op_number();
4767
4768 uint32_t flf_icall_opnum = zend_compile_frameless_icall_ex(NULL, zend_ast_get_list(args_ast), frameless_function, frameless_function_info, type);
4769
4770 zend_op *jmp_fl = &CG(active_op_array)->opcodes[jmp_fl_opnum];
4771 jmp_fl->op2.opline_num = jmp_fl_target;
4772 jmp_fl->extended_value = zend_alloc_cache_slot();
4773 zend_op *flf_icall = &CG(active_op_array)->opcodes[flf_icall_opnum];
4774 SET_NODE(flf_icall->result, result);
4775 zend_update_jump_target_to_next(jmp_end_opnum);
4776
4777 CG(context).in_jmp_frameless_branch = false;
4778 }
4779 }
4780 /* }}} */
4781
4782 static zend_op *zend_compile_rope_add(znode *result, uint32_t num, znode *elem_node);
4783 static zend_op *zend_compile_rope_add_ex(zend_op *opline, znode *result, uint32_t num, znode *elem_node);
4784 static void zend_compile_rope_finalize(znode *result, uint32_t j, zend_op *init_opline, zend_op *opline);
4785
zend_compile_func_sprintf(znode * result,zend_ast_list * args)4786 static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args) /* {{{ */
4787 {
4788 /* Bail out if we do not have a format string. */
4789 if (args->children < 1) {
4790 return FAILURE;
4791 }
4792
4793 zend_eval_const_expr(&args->child[0]);
4794 /* Bail out if the format string is not constant. */
4795 if (args->child[0]->kind != ZEND_AST_ZVAL) {
4796 return FAILURE;
4797 }
4798
4799 zval *format_string = zend_ast_get_zval(args->child[0]);
4800 if (Z_TYPE_P(format_string) != IS_STRING) {
4801 return FAILURE;
4802 }
4803 if (Z_STRLEN_P(format_string) >= 256) {
4804 return FAILURE;
4805 }
4806
4807 char *p;
4808 char *end;
4809 uint32_t placeholder_count;
4810
4811 placeholder_count = 0;
4812 p = Z_STRVAL_P(format_string);
4813 end = p + Z_STRLEN_P(format_string);
4814
4815 for (;;) {
4816 p = memchr(p, '%', end - p);
4817 if (!p) {
4818 break;
4819 }
4820
4821 char *q = p + 1;
4822 if (q == end) {
4823 return FAILURE;
4824 }
4825
4826 switch (*q) {
4827 case 's':
4828 case 'd':
4829 placeholder_count++;
4830 break;
4831 case '%':
4832 break;
4833 default:
4834 return FAILURE;
4835 }
4836
4837 p = q;
4838 p++;
4839 }
4840
4841 /* Bail out if the number of placeholders does not match the number of values. */
4842 if (placeholder_count != (args->children - 1)) {
4843 return FAILURE;
4844 }
4845
4846 /* Handle empty format strings. */
4847 if (Z_STRLEN_P(format_string) == 0) {
4848 result->op_type = IS_CONST;
4849 ZVAL_EMPTY_STRING(&result->u.constant);
4850
4851 return SUCCESS;
4852 }
4853
4854 znode *elements = NULL;
4855
4856 if (placeholder_count > 0) {
4857 elements = safe_emalloc(sizeof(*elements), placeholder_count, 0);
4858 }
4859
4860 /* Compile the value expressions first for error handling that is consistent
4861 * with a function call: Values that fail to convert to a string may emit errors.
4862 */
4863 for (uint32_t i = 0; i < placeholder_count; i++) {
4864 zend_compile_expr(elements + i, args->child[1 + i]);
4865 }
4866
4867 uint32_t rope_elements = 0;
4868 uint32_t rope_init_lineno = -1;
4869 zend_op *opline = NULL;
4870
4871 placeholder_count = 0;
4872 p = Z_STRVAL_P(format_string);
4873 end = p + Z_STRLEN_P(format_string);
4874 char *offset = p;
4875 for (;;) {
4876 p = memchr(p, '%', end - p);
4877 if (!p) {
4878 break;
4879 }
4880
4881 char *q = p + 1;
4882 ZEND_ASSERT(q < end);
4883 ZEND_ASSERT(*q == 's' || *q == 'd' || *q == '%');
4884
4885 if (*q == '%') {
4886 /* Optimization to not create a dedicated rope element for the literal '%':
4887 * Include the first '%' within the "constant" part instead of dropping the
4888 * full placeholder.
4889 */
4890 p++;
4891 }
4892
4893 if (p != offset) {
4894 znode const_node;
4895 const_node.op_type = IS_CONST;
4896 ZVAL_STRINGL(&const_node.u.constant, offset, p - offset);
4897 if (rope_elements == 0) {
4898 rope_init_lineno = get_next_op_number();
4899 }
4900 opline = zend_compile_rope_add(result, rope_elements++, &const_node);
4901 }
4902
4903 if (*q != '%') {
4904 switch (*q) {
4905 case 's':
4906 /* Perform the cast of constants when actually evaluating the corresponding placeholder
4907 * for correct error reporting.
4908 */
4909 if (elements[placeholder_count].op_type == IS_CONST) {
4910 if (Z_TYPE(elements[placeholder_count].u.constant) == IS_ARRAY) {
4911 zend_emit_op_tmp(&elements[placeholder_count], ZEND_CAST, &elements[placeholder_count], NULL)->extended_value = IS_STRING;
4912 } else {
4913 convert_to_string(&elements[placeholder_count].u.constant);
4914 }
4915 }
4916 break;
4917 case 'd':
4918 zend_emit_op_tmp(&elements[placeholder_count], ZEND_CAST, &elements[placeholder_count], NULL)->extended_value = IS_LONG;
4919 break;
4920 EMPTY_SWITCH_DEFAULT_CASE();
4921 }
4922
4923 if (rope_elements == 0) {
4924 rope_init_lineno = get_next_op_number();
4925 }
4926 opline = zend_compile_rope_add(result, rope_elements++, &elements[placeholder_count]);
4927
4928 placeholder_count++;
4929 }
4930
4931 p = q;
4932 p++;
4933 offset = p;
4934 }
4935 if (end != offset) {
4936 /* Add the constant part after the last placeholder. */
4937 znode const_node;
4938 const_node.op_type = IS_CONST;
4939 ZVAL_STRINGL(&const_node.u.constant, offset, end - offset);
4940 if (rope_elements == 0) {
4941 rope_init_lineno = get_next_op_number();
4942 }
4943 opline = zend_compile_rope_add(result, rope_elements++, &const_node);
4944 }
4945 ZEND_ASSERT(opline != NULL);
4946
4947 zend_op *init_opline = CG(active_op_array)->opcodes + rope_init_lineno;
4948 zend_compile_rope_finalize(result, rope_elements, init_opline, opline);
4949 efree(elements);
4950
4951 return SUCCESS;
4952 }
4953
zend_try_compile_special_func_ex(znode * result,zend_string * lcname,zend_ast_list * args,zend_function * fbc,uint32_t type)4954 static zend_result zend_try_compile_special_func_ex(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */
4955 {
4956 if (zend_string_equals_literal(lcname, "strlen")) {
4957 return zend_compile_func_strlen(result, args);
4958 } else if (zend_string_equals_literal(lcname, "is_null")) {
4959 return zend_compile_func_typecheck(result, args, IS_NULL);
4960 } else if (zend_string_equals_literal(lcname, "is_bool")) {
4961 return zend_compile_func_typecheck(result, args, _IS_BOOL);
4962 } else if (zend_string_equals_literal(lcname, "is_long")
4963 || zend_string_equals_literal(lcname, "is_int")
4964 || zend_string_equals_literal(lcname, "is_integer")
4965 ) {
4966 return zend_compile_func_typecheck(result, args, IS_LONG);
4967 } else if (zend_string_equals_literal(lcname, "is_float")
4968 || zend_string_equals_literal(lcname, "is_double")
4969 ) {
4970 return zend_compile_func_typecheck(result, args, IS_DOUBLE);
4971 } else if (zend_string_equals_literal(lcname, "is_string")) {
4972 return zend_compile_func_typecheck(result, args, IS_STRING);
4973 } else if (zend_string_equals_literal(lcname, "is_array")) {
4974 return zend_compile_func_typecheck(result, args, IS_ARRAY);
4975 } else if (zend_string_equals_literal(lcname, "is_object")) {
4976 return zend_compile_func_typecheck(result, args, IS_OBJECT);
4977 } else if (zend_string_equals_literal(lcname, "is_resource")) {
4978 return zend_compile_func_typecheck(result, args, IS_RESOURCE);
4979 } else if (zend_string_equals_literal(lcname, "is_scalar")) {
4980 return zend_compile_func_is_scalar(result, args);
4981 } else if (zend_string_equals_literal(lcname, "boolval")) {
4982 return zend_compile_func_cast(result, args, _IS_BOOL);
4983 } else if (zend_string_equals_literal(lcname, "intval")) {
4984 return zend_compile_func_cast(result, args, IS_LONG);
4985 } else if (zend_string_equals_literal(lcname, "floatval")
4986 || zend_string_equals_literal(lcname, "doubleval")
4987 ) {
4988 return zend_compile_func_cast(result, args, IS_DOUBLE);
4989 } else if (zend_string_equals_literal(lcname, "strval")) {
4990 return zend_compile_func_cast(result, args, IS_STRING);
4991 } else if (zend_string_equals_literal(lcname, "defined")) {
4992 return zend_compile_func_defined(result, args);
4993 } else if (zend_string_equals_literal(lcname, "chr") && type == BP_VAR_R) {
4994 return zend_compile_func_chr(result, args);
4995 } else if (zend_string_equals_literal(lcname, "ord") && type == BP_VAR_R) {
4996 return zend_compile_func_ord(result, args);
4997 } else if (zend_string_equals_literal(lcname, "call_user_func_array")) {
4998 return zend_compile_func_cufa(result, args, lcname);
4999 } else if (zend_string_equals_literal(lcname, "call_user_func")) {
5000 return zend_compile_func_cuf(result, args, lcname);
5001 } else if (zend_string_equals_literal(lcname, "in_array")) {
5002 return zend_compile_func_in_array(result, args);
5003 } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_COUNT))
5004 || zend_string_equals_literal(lcname, "sizeof")) {
5005 return zend_compile_func_count(result, args, lcname);
5006 } else if (zend_string_equals_literal(lcname, "get_class")) {
5007 return zend_compile_func_get_class(result, args);
5008 } else if (zend_string_equals_literal(lcname, "get_called_class")) {
5009 return zend_compile_func_get_called_class(result, args);
5010 } else if (zend_string_equals_literal(lcname, "gettype")) {
5011 return zend_compile_func_gettype(result, args);
5012 } else if (zend_string_equals_literal(lcname, "func_num_args")) {
5013 return zend_compile_func_num_args(result, args);
5014 } else if (zend_string_equals_literal(lcname, "func_get_args")) {
5015 return zend_compile_func_get_args(result, args);
5016 } else if (zend_string_equals_literal(lcname, "array_slice")) {
5017 return zend_compile_func_array_slice(result, args);
5018 } else if (zend_string_equals_literal(lcname, "array_key_exists")) {
5019 return zend_compile_func_array_key_exists(result, args);
5020 } else if (zend_string_equals_literal(lcname, "sprintf")) {
5021 return zend_compile_func_sprintf(result, args);
5022 } else {
5023 return FAILURE;
5024 }
5025 }
5026
zend_try_compile_special_func(znode * result,zend_string * lcname,zend_ast_list * args,zend_function * fbc,uint32_t type)5027 static zend_result zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */
5028 {
5029 if (CG(compiler_options) & ZEND_COMPILE_NO_BUILTINS) {
5030 return FAILURE;
5031 }
5032
5033 if (fbc->type != ZEND_INTERNAL_FUNCTION) {
5034 /* If the function is part of disabled_functions, it may be redeclared as a userland
5035 * function with a different implementation. Don't use the VM builtin in that case. */
5036 return FAILURE;
5037 }
5038
5039 if (zend_args_contain_unpack_or_named(args)) {
5040 return FAILURE;
5041 }
5042
5043 if (zend_try_compile_special_func_ex(result, lcname, args, fbc, type) == SUCCESS) {
5044 return SUCCESS;
5045 }
5046
5047 return zend_compile_frameless_icall(result, args, fbc, type) != (uint32_t)-1 ? SUCCESS : FAILURE;
5048 }
5049
zend_get_cstring_from_property_hook_kind(zend_property_hook_kind kind)5050 static const char *zend_get_cstring_from_property_hook_kind(zend_property_hook_kind kind) {
5051 switch (kind) {
5052 case ZEND_PROPERTY_HOOK_GET:
5053 return "get";
5054 case ZEND_PROPERTY_HOOK_SET:
5055 return "set";
5056 EMPTY_SWITCH_DEFAULT_CASE()
5057 }
5058 }
5059
zend_copy_unmangled_prop_name(zend_string * prop_name)5060 static zend_string *zend_copy_unmangled_prop_name(zend_string *prop_name)
5061 {
5062 if (ZSTR_VAL(prop_name)[0] != '\0') {
5063 return zend_string_copy(prop_name);
5064 } else {
5065 const char *unmangled = zend_get_unmangled_property_name(prop_name);
5066 return zend_string_init(unmangled, strlen(unmangled), /* persistent */ false);
5067 }
5068 }
5069
zend_compile_parent_property_hook_call(znode * result,zend_ast * ast,uint32_t type)5070 static bool zend_compile_parent_property_hook_call(znode *result, zend_ast *ast, uint32_t type)
5071 {
5072 ZEND_ASSERT(ast->kind == ZEND_AST_STATIC_CALL);
5073
5074 zend_ast *class_ast = ast->child[0];
5075 zend_ast *method_ast = ast->child[1];
5076
5077 /* Recognize parent::$prop::get() pattern. */
5078 if (class_ast->kind != ZEND_AST_STATIC_PROP
5079 || (class_ast->attr & ZEND_PARENTHESIZED_STATIC_PROP)
5080 || class_ast->child[0]->kind != ZEND_AST_ZVAL
5081 || Z_TYPE_P(zend_ast_get_zval(class_ast->child[0])) != IS_STRING
5082 || zend_get_class_fetch_type(zend_ast_get_str(class_ast->child[0])) != ZEND_FETCH_CLASS_PARENT
5083 || class_ast->child[1]->kind != ZEND_AST_ZVAL
5084 || method_ast->kind != ZEND_AST_ZVAL
5085 || Z_TYPE_P(zend_ast_get_zval(method_ast)) != IS_STRING
5086 || (!zend_string_equals_literal_ci(zend_ast_get_str(method_ast), "get")
5087 && !zend_string_equals_literal_ci(zend_ast_get_str(method_ast), "set"))) {
5088 return false;
5089 }
5090
5091 zend_class_entry *ce = CG(active_class_entry);
5092 if (!ce) {
5093 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"parent\" when no class scope is active");
5094 }
5095
5096 zend_ast *args_ast = ast->child[2];
5097 if (args_ast->kind == ZEND_AST_CALLABLE_CONVERT) {
5098 zend_error_noreturn(E_COMPILE_ERROR, "Cannot create Closure for parent property hook call");
5099 }
5100
5101 zend_string *property_name = zend_ast_get_str(class_ast->child[1]);
5102 zend_string *hook_name = zend_ast_get_str(method_ast);
5103 zend_property_hook_kind hook_kind = zend_get_property_hook_kind_from_name(hook_name);
5104 ZEND_ASSERT(hook_kind != (uint32_t)-1);
5105
5106 const zend_property_info *prop_info = CG(context).active_property_info;
5107 if (!prop_info) {
5108 zend_error_noreturn(E_COMPILE_ERROR, "Must not use parent::$%s::%s() outside a property hook",
5109 ZSTR_VAL(property_name), ZSTR_VAL(hook_name));
5110 }
5111
5112 const char *unmangled_prop_name = zend_get_unmangled_property_name(prop_info->name);
5113 if (!zend_string_equals_cstr(property_name, unmangled_prop_name, strlen(unmangled_prop_name))) {
5114 zend_error_noreturn(E_COMPILE_ERROR, "Must not use parent::$%s::%s() in a different property ($%s)",
5115 ZSTR_VAL(property_name), ZSTR_VAL(hook_name), unmangled_prop_name);
5116 }
5117 if (hook_kind != CG(context).active_property_hook_kind) {
5118 zend_error_noreturn(E_COMPILE_ERROR, "Must not use parent::$%s::%s() in a different property hook (%s)",
5119 ZSTR_VAL(property_name), ZSTR_VAL(hook_name), zend_get_cstring_from_property_hook_kind(CG(context).active_property_hook_kind));
5120 }
5121
5122 zend_op *opline = get_next_op();
5123 opline->opcode = ZEND_INIT_PARENT_PROPERTY_HOOK_CALL;
5124 opline->op1_type = IS_CONST;
5125 zend_string_copy(property_name);
5126 opline->op1.constant = zend_add_literal_string(&property_name);
5127 opline->op2.num = hook_kind;
5128
5129 zend_function *fbc = NULL;
5130 zend_compile_call_common(result, args_ast, fbc, zend_ast_get_lineno(method_ast));
5131
5132 return true;
5133 }
5134
zend_compile_call(znode * result,zend_ast * ast,uint32_t type)5135 static void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
5136 {
5137 zend_ast *name_ast = ast->child[0];
5138 zend_ast *args_ast = ast->child[1];
5139 bool is_callable_convert = args_ast->kind == ZEND_AST_CALLABLE_CONVERT;
5140
5141 znode name_node;
5142
5143 if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
5144 zend_compile_expr(&name_node, name_ast);
5145 zend_compile_dynamic_call(result, &name_node, args_ast, ast->lineno);
5146 return;
5147 }
5148
5149 {
5150 bool runtime_resolution = zend_compile_function_name(&name_node, name_ast);
5151 if (runtime_resolution) {
5152 if (zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "assert")
5153 && !is_callable_convert) {
5154 zend_compile_assert(result, zend_ast_get_list(args_ast), Z_STR(name_node.u.constant), NULL, ast->lineno);
5155 } else {
5156 zend_compile_ns_call(result, &name_node, args_ast, ast->lineno, type);
5157 }
5158 return;
5159 }
5160 }
5161
5162 {
5163 zval *name = &name_node.u.constant;
5164 zend_string *lcname;
5165 zend_function *fbc;
5166 zend_op *opline;
5167
5168 lcname = zend_string_tolower(Z_STR_P(name));
5169 zval *fbc_zv = zend_hash_find(CG(function_table), lcname);
5170 fbc = fbc_zv ? Z_PTR_P(fbc_zv) : NULL;
5171
5172 /* Special assert() handling should apply independently of compiler flags. */
5173 if (fbc && zend_string_equals_literal(lcname, "assert") && !is_callable_convert) {
5174 zend_compile_assert(result, zend_ast_get_list(args_ast), lcname, fbc, ast->lineno);
5175 zend_string_release(lcname);
5176 zval_ptr_dtor(&name_node.u.constant);
5177 return;
5178 }
5179
5180 if (!fbc
5181 || !fbc_is_finalized(fbc)
5182 || zend_compile_ignore_function(fbc, CG(active_op_array)->filename)) {
5183 zend_string_release_ex(lcname, 0);
5184 zend_compile_dynamic_call(result, &name_node, args_ast, ast->lineno);
5185 return;
5186 }
5187
5188 if (!is_callable_convert &&
5189 zend_try_compile_special_func(result, lcname,
5190 zend_ast_get_list(args_ast), fbc, type) == SUCCESS
5191 ) {
5192 zend_string_release_ex(lcname, 0);
5193 zval_ptr_dtor(&name_node.u.constant);
5194 return;
5195 }
5196
5197 zval_ptr_dtor(&name_node.u.constant);
5198 ZVAL_NEW_STR(&name_node.u.constant, lcname);
5199
5200 opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node);
5201 opline->result.num = zend_alloc_cache_slot();
5202
5203 /* Store offset to function from symbol table in op2.extra. */
5204 if (fbc->type == ZEND_INTERNAL_FUNCTION) {
5205 Bucket *fbc_bucket = (Bucket*)((uintptr_t)fbc_zv - XtOffsetOf(Bucket, val));
5206 Z_EXTRA_P(CT_CONSTANT(opline->op2)) = fbc_bucket - CG(function_table)->arData;
5207 }
5208
5209 zend_compile_call_common(result, args_ast, fbc, ast->lineno);
5210 }
5211 }
5212 /* }}} */
5213
zend_compile_method_call(znode * result,zend_ast * ast,uint32_t type)5214 static void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
5215 {
5216 zend_ast *obj_ast = ast->child[0];
5217 zend_ast *method_ast = ast->child[1];
5218 zend_ast *args_ast = ast->child[2];
5219
5220 znode obj_node, method_node;
5221 zend_op *opline;
5222 zend_function *fbc = NULL;
5223 bool nullsafe = ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL;
5224 uint32_t short_circuiting_checkpoint = zend_short_circuiting_checkpoint();
5225
5226 if (is_this_fetch(obj_ast)) {
5227 if (this_guaranteed_exists()) {
5228 obj_node.op_type = IS_UNUSED;
5229 } else {
5230 zend_emit_op(&obj_node, ZEND_FETCH_THIS, NULL, NULL);
5231 }
5232 CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
5233
5234 /* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
5235 * check for a nullsafe access. */
5236 } else {
5237 zend_short_circuiting_mark_inner(obj_ast);
5238 zend_compile_expr(&obj_node, obj_ast);
5239 if (nullsafe) {
5240 zend_emit_jmp_null(&obj_node, type);
5241 }
5242 }
5243
5244 zend_compile_expr(&method_node, method_ast);
5245 opline = zend_emit_op(NULL, ZEND_INIT_METHOD_CALL, &obj_node, NULL);
5246
5247 if (method_node.op_type == IS_CONST) {
5248 if (Z_TYPE(method_node.u.constant) != IS_STRING) {
5249 zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
5250 }
5251
5252 opline->op2_type = IS_CONST;
5253 opline->op2.constant = zend_add_func_name_literal(
5254 Z_STR(method_node.u.constant));
5255 opline->result.num = zend_alloc_cache_slots(2);
5256 } else {
5257 SET_NODE(opline->op2, &method_node);
5258 }
5259
5260 /* Check if this calls a known method on $this */
5261 if (opline->op1_type == IS_UNUSED && opline->op2_type == IS_CONST &&
5262 CG(active_class_entry) && zend_is_scope_known()) {
5263 zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op2) + 1);
5264 fbc = zend_hash_find_ptr(&CG(active_class_entry)->function_table, lcname);
5265
5266 /* We only know the exact method that is being called if it is either private or final.
5267 * Otherwise an overriding method in a child class may be called. */
5268 if (fbc && !(fbc->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_FINAL))) {
5269 fbc = NULL;
5270 }
5271 }
5272
5273 if (zend_compile_call_common(result, args_ast, fbc, zend_ast_get_lineno(method_ast))) {
5274 if (short_circuiting_checkpoint != zend_short_circuiting_checkpoint()) {
5275 zend_error_noreturn(E_COMPILE_ERROR,
5276 "Cannot combine nullsafe operator with Closure creation");
5277 }
5278 }
5279 }
5280 /* }}} */
5281
zend_is_constructor(zend_string * name)5282 static bool zend_is_constructor(zend_string *name) /* {{{ */
5283 {
5284 return zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME);
5285 }
5286 /* }}} */
5287
zend_get_compatible_func_or_null(zend_class_entry * ce,zend_string * lcname)5288 static zend_function *zend_get_compatible_func_or_null(zend_class_entry *ce, zend_string *lcname) /* {{{ */
5289 {
5290 zend_function *fbc = zend_hash_find_ptr(&ce->function_table, lcname);
5291 if (!fbc || (fbc->common.fn_flags & ZEND_ACC_PUBLIC) || ce == CG(active_class_entry)) {
5292 return fbc;
5293 }
5294
5295 if (!(fbc->common.fn_flags & ZEND_ACC_PRIVATE)
5296 && (fbc->common.scope->ce_flags & ZEND_ACC_LINKED)
5297 && (!CG(active_class_entry) || (CG(active_class_entry)->ce_flags & ZEND_ACC_LINKED))
5298 && zend_check_protected(zend_get_function_root_class(fbc), CG(active_class_entry))) {
5299 return fbc;
5300 }
5301
5302 return NULL;
5303 }
5304 /* }}} */
5305
zend_compile_static_call(znode * result,zend_ast * ast,uint32_t type)5306 static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
5307 {
5308 zend_ast *class_ast = ast->child[0];
5309 zend_ast *method_ast = ast->child[1];
5310 zend_ast *args_ast = ast->child[2];
5311
5312 znode class_node, method_node;
5313 zend_op *opline;
5314 zend_function *fbc = NULL;
5315
5316 if (zend_compile_parent_property_hook_call(result, ast, type)) {
5317 return;
5318 }
5319
5320 zend_short_circuiting_mark_inner(class_ast);
5321 zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
5322
5323 zend_compile_expr(&method_node, method_ast);
5324
5325 if (method_node.op_type == IS_CONST) {
5326 zval *name = &method_node.u.constant;
5327 if (Z_TYPE_P(name) != IS_STRING) {
5328 zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
5329 }
5330 if (zend_is_constructor(Z_STR_P(name))) {
5331 zval_ptr_dtor(name);
5332 method_node.op_type = IS_UNUSED;
5333 }
5334 }
5335
5336 opline = get_next_op();
5337 opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
5338
5339 zend_set_class_name_op1(opline, &class_node);
5340
5341 if (method_node.op_type == IS_CONST) {
5342 opline->op2_type = IS_CONST;
5343 opline->op2.constant = zend_add_func_name_literal(
5344 Z_STR(method_node.u.constant));
5345 opline->result.num = zend_alloc_cache_slots(2);
5346 } else {
5347 if (opline->op1_type == IS_CONST) {
5348 opline->result.num = zend_alloc_cache_slot();
5349 }
5350 SET_NODE(opline->op2, &method_node);
5351 }
5352
5353 /* Check if we already know which method we're calling */
5354 if (opline->op2_type == IS_CONST) {
5355 zend_class_entry *ce = NULL;
5356 if (opline->op1_type == IS_CONST) {
5357 zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op1) + 1);
5358 ce = zend_hash_find_ptr(CG(class_table), lcname);
5359 if (ce) {
5360 if (zend_compile_ignore_class(ce, CG(active_op_array)->filename)) {
5361 ce = NULL;
5362 }
5363 } else if (CG(active_class_entry)
5364 && zend_string_equals_ci(CG(active_class_entry)->name, lcname)) {
5365 ce = CG(active_class_entry);
5366 }
5367 } else if (opline->op1_type == IS_UNUSED
5368 && (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF
5369 && zend_is_scope_known()) {
5370 ce = CG(active_class_entry);
5371 }
5372 if (ce) {
5373 zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op2) + 1);
5374 fbc = zend_get_compatible_func_or_null(ce, lcname);
5375 }
5376 }
5377
5378 zend_compile_call_common(result, args_ast, fbc, zend_ast_get_lineno(method_ast));
5379 }
5380 /* }}} */
5381
5382 static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel);
5383
zend_compile_new(znode * result,zend_ast * ast)5384 static void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */
5385 {
5386 zend_ast *class_ast = ast->child[0];
5387 zend_ast *args_ast = ast->child[1];
5388
5389 znode class_node, ctor_result;
5390 zend_op *opline;
5391
5392 if (class_ast->kind == ZEND_AST_CLASS) {
5393 /* anon class declaration */
5394 zend_compile_class_decl(&class_node, class_ast, 0);
5395 } else {
5396 zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
5397 }
5398
5399 opline = zend_emit_op(result, ZEND_NEW, NULL, NULL);
5400
5401 if (class_node.op_type == IS_CONST) {
5402 opline->op1_type = IS_CONST;
5403 opline->op1.constant = zend_add_class_name_literal(
5404 Z_STR(class_node.u.constant));
5405 opline->op2.num = zend_alloc_cache_slot();
5406 } else {
5407 SET_NODE(opline->op1, &class_node);
5408 }
5409
5410 zend_compile_call_common(&ctor_result, args_ast, NULL, ast->lineno);
5411 zend_do_free(&ctor_result);
5412 }
5413 /* }}} */
5414
zend_compile_clone(znode * result,zend_ast * ast)5415 static void zend_compile_clone(znode *result, zend_ast *ast) /* {{{ */
5416 {
5417 zend_ast *obj_ast = ast->child[0];
5418
5419 znode obj_node;
5420 zend_compile_expr(&obj_node, obj_ast);
5421
5422 zend_emit_op_tmp(result, ZEND_CLONE, &obj_node, NULL);
5423 }
5424 /* }}} */
5425
zend_compile_global_var(zend_ast * ast)5426 static void zend_compile_global_var(zend_ast *ast) /* {{{ */
5427 {
5428 zend_ast *var_ast = ast->child[0];
5429 zend_ast *name_ast = var_ast->child[0];
5430
5431 znode name_node, result;
5432
5433 zend_compile_expr(&name_node, name_ast);
5434 if (name_node.op_type == IS_CONST) {
5435 convert_to_string(&name_node.u.constant);
5436 }
5437
5438 // TODO(GLOBALS) Forbid "global $GLOBALS"?
5439 if (is_this_fetch(var_ast)) {
5440 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable");
5441 } else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
5442 zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node);
5443 opline->extended_value = zend_alloc_cache_slot();
5444 } else {
5445 /* name_ast should be evaluated only. FETCH_GLOBAL_LOCK instructs FETCH_W
5446 * to not free the name_node operand, so it can be reused in the following
5447 * ASSIGN_REF, which then frees it. */
5448 zend_op *opline = zend_emit_op(&result, ZEND_FETCH_W, &name_node, NULL);
5449 opline->extended_value = ZEND_FETCH_GLOBAL_LOCK;
5450
5451 if (name_node.op_type == IS_CONST) {
5452 zend_string_addref(Z_STR(name_node.u.constant));
5453 }
5454
5455 zend_emit_assign_ref_znode(
5456 zend_ast_create(ZEND_AST_VAR, zend_ast_create_znode(&name_node)),
5457 &result
5458 );
5459 }
5460 }
5461 /* }}} */
5462
zend_compile_static_var_common(zend_string * var_name,zval * value,uint32_t mode)5463 static void zend_compile_static_var_common(zend_string *var_name, zval *value, uint32_t mode) /* {{{ */
5464 {
5465 zend_op *opline;
5466 if (!CG(active_op_array)->static_variables) {
5467 if (CG(active_op_array)->scope) {
5468 CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
5469 }
5470 CG(active_op_array)->static_variables = zend_new_array(8);
5471 }
5472
5473 value = zend_hash_update(CG(active_op_array)->static_variables, var_name, value);
5474
5475 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
5476 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
5477 }
5478
5479 opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, NULL);
5480 opline->op1_type = IS_CV;
5481 opline->op1.var = lookup_cv(var_name);
5482 opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | mode;
5483 }
5484 /* }}} */
5485
zend_compile_static_var(zend_ast * ast)5486 static void zend_compile_static_var(zend_ast *ast) /* {{{ */
5487 {
5488 zend_ast *var_ast = ast->child[0];
5489 zend_string *var_name = zend_ast_get_str(var_ast);
5490
5491 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
5492 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
5493 }
5494
5495 if (!CG(active_op_array)->static_variables) {
5496 if (CG(active_op_array)->scope) {
5497 CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
5498 }
5499 CG(active_op_array)->static_variables = zend_new_array(8);
5500 }
5501
5502 if (zend_hash_exists(CG(active_op_array)->static_variables, var_name)) {
5503 zend_error_noreturn_unchecked(E_COMPILE_ERROR, "Duplicate declaration of static variable $%S", var_name);
5504 }
5505
5506 zend_eval_const_expr(&ast->child[1]);
5507 zend_ast *value_ast = ast->child[1];
5508
5509 if (!value_ast || value_ast->kind == ZEND_AST_ZVAL) {
5510 zval *value_zv = value_ast
5511 ? zend_ast_get_zval(value_ast)
5512 : &EG(uninitialized_zval);
5513 Z_TRY_ADDREF_P(value_zv);
5514 zend_compile_static_var_common(var_name, value_zv, ZEND_BIND_REF);
5515 } else {
5516 zend_op *opline;
5517
5518 zval *placeholder_ptr = zend_hash_update(CG(active_op_array)->static_variables, var_name, &EG(uninitialized_zval));
5519 uint32_t placeholder_offset = (uint32_t)((char*)placeholder_ptr - (char*)CG(active_op_array)->static_variables->arData);
5520
5521 uint32_t static_def_jmp_opnum = get_next_op_number();
5522 opline = zend_emit_op(NULL, ZEND_BIND_INIT_STATIC_OR_JMP, NULL, NULL);
5523 opline->op1_type = IS_CV;
5524 opline->op1.var = lookup_cv(var_name);
5525 opline->extended_value = placeholder_offset;
5526
5527 znode expr;
5528 zend_compile_expr(&expr, value_ast);
5529
5530 opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &expr);
5531 opline->op1_type = IS_CV;
5532 opline->op1.var = lookup_cv(var_name);
5533 opline->extended_value = placeholder_offset | ZEND_BIND_REF;
5534
5535 zend_update_jump_target_to_next(static_def_jmp_opnum);
5536 }
5537 }
5538 /* }}} */
5539
zend_compile_unset(zend_ast * ast)5540 static void zend_compile_unset(zend_ast *ast) /* {{{ */
5541 {
5542 zend_ast *var_ast = ast->child[0];
5543 znode var_node;
5544 zend_op *opline;
5545
5546 zend_ensure_writable_variable(var_ast);
5547
5548 if (is_global_var_fetch(var_ast)) {
5549 if (!var_ast->child[1]) {
5550 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for unsetting");
5551 }
5552
5553 zend_compile_expr(&var_node, var_ast->child[1]);
5554 if (var_node.op_type == IS_CONST) {
5555 convert_to_string(&var_node.u.constant);
5556 }
5557
5558 opline = zend_emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL);
5559 opline->extended_value = ZEND_FETCH_GLOBAL;
5560 return;
5561 }
5562
5563 switch (var_ast->kind) {
5564 case ZEND_AST_VAR:
5565 if (is_this_fetch(var_ast)) {
5566 zend_error_noreturn(E_COMPILE_ERROR, "Cannot unset $this");
5567 } else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
5568 opline = zend_emit_op(NULL, ZEND_UNSET_CV, &var_node, NULL);
5569 } else {
5570 opline = zend_compile_simple_var_no_cv(NULL, var_ast, BP_VAR_UNSET, 0);
5571 opline->opcode = ZEND_UNSET_VAR;
5572 }
5573 return;
5574 case ZEND_AST_DIM:
5575 opline = zend_compile_dim(NULL, var_ast, BP_VAR_UNSET, /* by_ref */ false);
5576 opline->opcode = ZEND_UNSET_DIM;
5577 return;
5578 case ZEND_AST_PROP:
5579 case ZEND_AST_NULLSAFE_PROP:
5580 opline = zend_compile_prop(NULL, var_ast, BP_VAR_UNSET, 0);
5581 opline->opcode = ZEND_UNSET_OBJ;
5582 return;
5583 case ZEND_AST_STATIC_PROP:
5584 opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_UNSET, 0, 0);
5585 opline->opcode = ZEND_UNSET_STATIC_PROP;
5586 return;
5587 EMPTY_SWITCH_DEFAULT_CASE()
5588 }
5589 }
5590 /* }}} */
5591
zend_handle_loops_and_finally_ex(zend_long depth,znode * return_value)5592 static bool zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value) /* {{{ */
5593 {
5594 zend_loop_var *base;
5595 zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
5596
5597 if (!loop_var) {
5598 return 1;
5599 }
5600 base = zend_stack_base(&CG(loop_var_stack));
5601 for (; loop_var >= base; loop_var--) {
5602 if (loop_var->opcode == ZEND_FAST_CALL) {
5603 zend_op *opline = get_next_op();
5604
5605 opline->opcode = ZEND_FAST_CALL;
5606 opline->result_type = IS_TMP_VAR;
5607 opline->result.var = loop_var->var_num;
5608 if (return_value) {
5609 SET_NODE(opline->op2, return_value);
5610 }
5611 opline->op1.num = loop_var->try_catch_offset;
5612 } else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) {
5613 zend_op *opline = get_next_op();
5614 opline->opcode = ZEND_DISCARD_EXCEPTION;
5615 opline->op1_type = IS_TMP_VAR;
5616 opline->op1.var = loop_var->var_num;
5617 } else if (loop_var->opcode == ZEND_RETURN) {
5618 /* Stack separator */
5619 break;
5620 } else if (depth <= 1) {
5621 return 1;
5622 } else if (loop_var->opcode == ZEND_NOP) {
5623 /* Loop doesn't have freeable variable */
5624 depth--;
5625 } else {
5626 zend_op *opline;
5627
5628 ZEND_ASSERT(loop_var->var_type & (IS_VAR|IS_TMP_VAR));
5629 opline = get_next_op();
5630 opline->opcode = loop_var->opcode;
5631 opline->op1_type = loop_var->var_type;
5632 opline->op1.var = loop_var->var_num;
5633 opline->extended_value = ZEND_FREE_ON_RETURN;
5634 depth--;
5635 }
5636 }
5637 return (depth == 0);
5638 }
5639 /* }}} */
5640
zend_handle_loops_and_finally(znode * return_value)5641 static bool zend_handle_loops_and_finally(znode *return_value) /* {{{ */
5642 {
5643 return zend_handle_loops_and_finally_ex(zend_stack_count(&CG(loop_var_stack)) + 1, return_value);
5644 }
5645 /* }}} */
5646
zend_has_finally_ex(zend_long depth)5647 static bool zend_has_finally_ex(zend_long depth) /* {{{ */
5648 {
5649 zend_loop_var *base;
5650 zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
5651
5652 if (!loop_var) {
5653 return 0;
5654 }
5655 base = zend_stack_base(&CG(loop_var_stack));
5656 for (; loop_var >= base; loop_var--) {
5657 if (loop_var->opcode == ZEND_FAST_CALL) {
5658 return 1;
5659 } else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) {
5660 } else if (loop_var->opcode == ZEND_RETURN) {
5661 /* Stack separator */
5662 return 0;
5663 } else if (depth <= 1) {
5664 return 0;
5665 } else {
5666 depth--;
5667 }
5668 }
5669 return 0;
5670 }
5671 /* }}} */
5672
zend_has_finally(void)5673 static bool zend_has_finally(void) /* {{{ */
5674 {
5675 return zend_has_finally_ex(zend_stack_count(&CG(loop_var_stack)) + 1);
5676 }
5677 /* }}} */
5678
zend_compile_return(zend_ast * ast)5679 static void zend_compile_return(zend_ast *ast) /* {{{ */
5680 {
5681 zend_ast *expr_ast = ast->child[0];
5682 bool is_generator = (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0;
5683 bool by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
5684
5685 znode expr_node;
5686 zend_op *opline;
5687
5688 if (is_generator) {
5689 /* For generators the by-ref flag refers to yields, not returns */
5690 by_ref = 0;
5691 }
5692
5693 if (!expr_ast) {
5694 expr_node.op_type = IS_CONST;
5695 ZVAL_NULL(&expr_node.u.constant);
5696 } else if (by_ref && zend_is_variable(expr_ast)) {
5697 zend_assert_not_short_circuited(expr_ast);
5698 zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
5699 } else {
5700 zend_compile_expr(&expr_node, expr_ast);
5701 }
5702
5703 if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)
5704 && (expr_node.op_type == IS_CV || (by_ref && expr_node.op_type == IS_VAR))
5705 && zend_has_finally()) {
5706 /* Copy return value into temporary VAR to avoid modification in finally code */
5707 if (by_ref) {
5708 zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL);
5709 } else {
5710 zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &expr_node, NULL);
5711 }
5712 }
5713
5714 /* Generator return types are handled separately */
5715 if (!is_generator && (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
5716 zend_emit_return_type_check(
5717 expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1, 0);
5718 }
5719
5720 zend_handle_loops_and_finally((expr_node.op_type & (IS_TMP_VAR | IS_VAR)) ? &expr_node : NULL);
5721
5722 opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
5723 &expr_node, NULL);
5724
5725 if (by_ref && expr_ast) {
5726 if (zend_is_call(expr_ast)) {
5727 opline->extended_value = ZEND_RETURNS_FUNCTION;
5728 } else if (!zend_is_variable(expr_ast) || zend_ast_is_short_circuited(expr_ast)) {
5729 opline->extended_value = ZEND_RETURNS_VALUE;
5730 }
5731 }
5732 }
5733 /* }}} */
5734
zend_compile_echo(zend_ast * ast)5735 static void zend_compile_echo(zend_ast *ast) /* {{{ */
5736 {
5737 zend_op *opline;
5738 zend_ast *expr_ast = ast->child[0];
5739
5740 znode expr_node;
5741 zend_compile_expr(&expr_node, expr_ast);
5742
5743 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL);
5744 opline->extended_value = 0;
5745 }
5746 /* }}} */
5747
zend_compile_throw(znode * result,zend_ast * ast)5748 static void zend_compile_throw(znode *result, zend_ast *ast) /* {{{ */
5749 {
5750 zend_ast *expr_ast = ast->child[0];
5751
5752 znode expr_node;
5753 zend_compile_expr(&expr_node, expr_ast);
5754
5755 zend_op *opline = zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
5756 if (result) {
5757 /* Mark this as an "expression throw" for opcache. */
5758 opline->extended_value = ZEND_THROW_IS_EXPR;
5759 result->op_type = IS_CONST;
5760 ZVAL_TRUE(&result->u.constant);
5761 }
5762 }
5763 /* }}} */
5764
zend_compile_break_continue(zend_ast * ast)5765 static void zend_compile_break_continue(zend_ast *ast) /* {{{ */
5766 {
5767 zend_ast *depth_ast = ast->child[0];
5768
5769 zend_op *opline;
5770 zend_long depth;
5771
5772 ZEND_ASSERT(ast->kind == ZEND_AST_BREAK || ast->kind == ZEND_AST_CONTINUE);
5773
5774 if (depth_ast) {
5775 zval *depth_zv;
5776 if (depth_ast->kind != ZEND_AST_ZVAL) {
5777 zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-integer operand "
5778 "is no longer supported", ast->kind == ZEND_AST_BREAK ? "break" : "continue");
5779 }
5780
5781 depth_zv = zend_ast_get_zval(depth_ast);
5782 if (Z_TYPE_P(depth_zv) != IS_LONG || Z_LVAL_P(depth_zv) < 1) {
5783 zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive integers",
5784 ast->kind == ZEND_AST_BREAK ? "break" : "continue");
5785 }
5786
5787 depth = Z_LVAL_P(depth_zv);
5788 } else {
5789 depth = 1;
5790 }
5791
5792 if (CG(context).current_brk_cont == -1) {
5793 zend_error_noreturn(E_COMPILE_ERROR, "'%s' not in the 'loop' or 'switch' context",
5794 ast->kind == ZEND_AST_BREAK ? "break" : "continue");
5795 } else {
5796 if (!zend_handle_loops_and_finally_ex(depth, NULL)) {
5797 zend_error_noreturn(E_COMPILE_ERROR, "Cannot '%s' " ZEND_LONG_FMT " level%s",
5798 ast->kind == ZEND_AST_BREAK ? "break" : "continue",
5799 depth, depth == 1 ? "" : "s");
5800 }
5801 }
5802
5803 if (ast->kind == ZEND_AST_CONTINUE) {
5804 int d, cur = CG(context).current_brk_cont;
5805 for (d = depth - 1; d > 0; d--) {
5806 cur = CG(context).brk_cont_array[cur].parent;
5807 ZEND_ASSERT(cur != -1);
5808 }
5809
5810 if (CG(context).brk_cont_array[cur].is_switch) {
5811 if (depth == 1) {
5812 if (CG(context).brk_cont_array[cur].parent == -1) {
5813 zend_error(E_WARNING,
5814 "\"continue\" targeting switch is equivalent to \"break\"");
5815 } else {
5816 zend_error(E_WARNING,
5817 "\"continue\" targeting switch is equivalent to \"break\". " \
5818 "Did you mean to use \"continue " ZEND_LONG_FMT "\"?",
5819 depth + 1);
5820 }
5821 } else {
5822 if (CG(context).brk_cont_array[cur].parent == -1) {
5823 zend_error(E_WARNING,
5824 "\"continue " ZEND_LONG_FMT "\" targeting switch is equivalent to \"break " ZEND_LONG_FMT "\"",
5825 depth, depth);
5826 } else {
5827 zend_error(E_WARNING,
5828 "\"continue " ZEND_LONG_FMT "\" targeting switch is equivalent to \"break " ZEND_LONG_FMT "\". " \
5829 "Did you mean to use \"continue " ZEND_LONG_FMT "\"?",
5830 depth, depth, depth + 1);
5831 }
5832 }
5833 }
5834 }
5835
5836 opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT, NULL, NULL);
5837 opline->op1.num = CG(context).current_brk_cont;
5838 opline->op2.num = depth;
5839 }
5840 /* }}} */
5841
zend_resolve_goto_label(zend_op_array * op_array,zend_op * opline)5842 void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline) /* {{{ */
5843 {
5844 zend_label *dest;
5845 int current, remove_oplines = opline->op1.num;
5846 zval *label;
5847 uint32_t opnum = opline - op_array->opcodes;
5848
5849 label = CT_CONSTANT_EX(op_array, opline->op2.constant);
5850 if (CG(context).labels == NULL ||
5851 (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL
5852 ) {
5853 CG(in_compilation) = 1;
5854 CG(active_op_array) = op_array;
5855 CG(zend_lineno) = opline->lineno;
5856 zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
5857 }
5858
5859 zval_ptr_dtor_str(label);
5860 ZVAL_NULL(label);
5861
5862 current = opline->extended_value;
5863 for (; current != dest->brk_cont; current = CG(context).brk_cont_array[current].parent) {
5864 if (current == -1) {
5865 CG(in_compilation) = 1;
5866 CG(active_op_array) = op_array;
5867 CG(zend_lineno) = opline->lineno;
5868 zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
5869 }
5870 if (CG(context).brk_cont_array[current].start >= 0) {
5871 remove_oplines--;
5872 }
5873 }
5874
5875 for (current = 0; current < op_array->last_try_catch; ++current) {
5876 zend_try_catch_element *elem = &op_array->try_catch_array[current];
5877 if (elem->try_op > opnum) {
5878 break;
5879 }
5880 if (elem->finally_op && opnum < elem->finally_op - 1
5881 && (dest->opline_num > elem->finally_end || dest->opline_num < elem->try_op)
5882 ) {
5883 remove_oplines--;
5884 }
5885 }
5886
5887 opline->opcode = ZEND_JMP;
5888 SET_UNUSED(opline->op1);
5889 SET_UNUSED(opline->op2);
5890 SET_UNUSED(opline->result);
5891 opline->op1.opline_num = dest->opline_num;
5892 opline->extended_value = 0;
5893
5894 ZEND_ASSERT(remove_oplines >= 0);
5895 while (remove_oplines--) {
5896 opline--;
5897 MAKE_NOP(opline);
5898 ZEND_VM_SET_OPCODE_HANDLER(opline);
5899 }
5900 }
5901 /* }}} */
5902
zend_compile_goto(zend_ast * ast)5903 static void zend_compile_goto(zend_ast *ast) /* {{{ */
5904 {
5905 zend_ast *label_ast = ast->child[0];
5906 znode label_node;
5907 zend_op *opline;
5908
5909 zend_compile_expr(&label_node, label_ast);
5910
5911 /* Label resolution and unwinding adjustments happen in pass two. */
5912 uint32_t opnum_start = get_next_op_number();
5913 zend_handle_loops_and_finally(NULL);
5914 opline = zend_emit_op(NULL, ZEND_GOTO, NULL, &label_node);
5915 opline->op1.num = get_next_op_number() - opnum_start - 1;
5916 opline->extended_value = CG(context).current_brk_cont;
5917 }
5918 /* }}} */
5919
zend_compile_label(zend_ast * ast)5920 static void zend_compile_label(zend_ast *ast) /* {{{ */
5921 {
5922 zend_string *label = zend_ast_get_str(ast->child[0]);
5923 zend_label dest;
5924
5925 if (!CG(context).labels) {
5926 ALLOC_HASHTABLE(CG(context).labels);
5927 zend_hash_init(CG(context).labels, 8, NULL, label_ptr_dtor, 0);
5928 }
5929
5930 dest.brk_cont = CG(context).current_brk_cont;
5931 dest.opline_num = get_next_op_number();
5932
5933 if (!zend_hash_add_mem(CG(context).labels, label, &dest, sizeof(zend_label))) {
5934 zend_error_noreturn(E_COMPILE_ERROR, "Label '%s' already defined", ZSTR_VAL(label));
5935 }
5936 }
5937 /* }}} */
5938
zend_compile_while(zend_ast * ast)5939 static void zend_compile_while(zend_ast *ast) /* {{{ */
5940 {
5941 zend_ast *cond_ast = ast->child[0];
5942 zend_ast *stmt_ast = ast->child[1];
5943 znode cond_node;
5944 uint32_t opnum_start, opnum_jmp, opnum_cond;
5945
5946 opnum_jmp = zend_emit_jump(0);
5947
5948 zend_begin_loop(ZEND_NOP, NULL, 0);
5949
5950 opnum_start = get_next_op_number();
5951 zend_compile_stmt(stmt_ast);
5952
5953 opnum_cond = get_next_op_number();
5954 zend_update_jump_target(opnum_jmp, opnum_cond);
5955 zend_compile_expr(&cond_node, cond_ast);
5956
5957 zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start);
5958
5959 zend_end_loop(opnum_cond, NULL);
5960 }
5961 /* }}} */
5962
zend_compile_do_while(zend_ast * ast)5963 static void zend_compile_do_while(zend_ast *ast) /* {{{ */
5964 {
5965 zend_ast *stmt_ast = ast->child[0];
5966 zend_ast *cond_ast = ast->child[1];
5967
5968 znode cond_node;
5969 uint32_t opnum_start, opnum_cond;
5970
5971 zend_begin_loop(ZEND_NOP, NULL, 0);
5972
5973 opnum_start = get_next_op_number();
5974 zend_compile_stmt(stmt_ast);
5975
5976 opnum_cond = get_next_op_number();
5977 zend_compile_expr(&cond_node, cond_ast);
5978
5979 zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start);
5980
5981 zend_end_loop(opnum_cond, NULL);
5982 }
5983 /* }}} */
5984
zend_compile_expr_list(znode * result,zend_ast * ast)5985 static void zend_compile_expr_list(znode *result, zend_ast *ast) /* {{{ */
5986 {
5987 zend_ast_list *list;
5988 uint32_t i;
5989
5990 result->op_type = IS_CONST;
5991 ZVAL_TRUE(&result->u.constant);
5992
5993 if (!ast) {
5994 return;
5995 }
5996
5997 list = zend_ast_get_list(ast);
5998 for (i = 0; i < list->children; ++i) {
5999 zend_ast *expr_ast = list->child[i];
6000
6001 zend_do_free(result);
6002 zend_compile_expr(result, expr_ast);
6003 }
6004 }
6005 /* }}} */
6006
zend_compile_for(zend_ast * ast)6007 static void zend_compile_for(zend_ast *ast) /* {{{ */
6008 {
6009 zend_ast *init_ast = ast->child[0];
6010 zend_ast *cond_ast = ast->child[1];
6011 zend_ast *loop_ast = ast->child[2];
6012 zend_ast *stmt_ast = ast->child[3];
6013
6014 znode result;
6015 uint32_t opnum_start, opnum_jmp, opnum_loop;
6016
6017 zend_compile_expr_list(&result, init_ast);
6018 zend_do_free(&result);
6019
6020 opnum_jmp = zend_emit_jump(0);
6021
6022 zend_begin_loop(ZEND_NOP, NULL, 0);
6023
6024 opnum_start = get_next_op_number();
6025 zend_compile_stmt(stmt_ast);
6026
6027 opnum_loop = get_next_op_number();
6028 zend_compile_expr_list(&result, loop_ast);
6029 zend_do_free(&result);
6030
6031 zend_update_jump_target_to_next(opnum_jmp);
6032 zend_compile_expr_list(&result, cond_ast);
6033 zend_do_extended_stmt();
6034
6035 zend_emit_cond_jump(ZEND_JMPNZ, &result, opnum_start);
6036
6037 zend_end_loop(opnum_loop, NULL);
6038 }
6039 /* }}} */
6040
zend_compile_foreach(zend_ast * ast)6041 static void zend_compile_foreach(zend_ast *ast) /* {{{ */
6042 {
6043 zend_ast *expr_ast = ast->child[0];
6044 zend_ast *value_ast = ast->child[1];
6045 zend_ast *key_ast = ast->child[2];
6046 zend_ast *stmt_ast = ast->child[3];
6047 bool by_ref = value_ast->kind == ZEND_AST_REF;
6048 bool is_variable = zend_is_variable(expr_ast) && zend_can_write_to_variable(expr_ast);
6049
6050 znode expr_node, reset_node, value_node, key_node;
6051 zend_op *opline;
6052 uint32_t opnum_reset, opnum_fetch;
6053
6054 if (key_ast) {
6055 if (key_ast->kind == ZEND_AST_REF) {
6056 zend_error_noreturn(E_COMPILE_ERROR, "Key element cannot be a reference");
6057 }
6058 if (key_ast->kind == ZEND_AST_ARRAY) {
6059 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use list as key element");
6060 }
6061 }
6062
6063 if (by_ref) {
6064 value_ast = value_ast->child[0];
6065 }
6066
6067 if (value_ast->kind == ZEND_AST_ARRAY && zend_propagate_list_refs(value_ast)) {
6068 by_ref = 1;
6069 }
6070
6071 if (by_ref && is_variable) {
6072 zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
6073 } else {
6074 zend_compile_expr(&expr_node, expr_ast);
6075 }
6076
6077 if (by_ref) {
6078 zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W);
6079 }
6080
6081 opnum_reset = get_next_op_number();
6082 opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
6083
6084 zend_begin_loop(ZEND_FE_FREE, &reset_node, 0);
6085
6086 opnum_fetch = get_next_op_number();
6087 opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
6088
6089 if (is_this_fetch(value_ast)) {
6090 zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
6091 } else if (value_ast->kind == ZEND_AST_VAR &&
6092 zend_try_compile_cv(&value_node, value_ast) == SUCCESS) {
6093 SET_NODE(opline->op2, &value_node);
6094 } else {
6095 opline->op2_type = IS_VAR;
6096 opline->op2.var = get_temporary_variable();
6097 GET_NODE(&value_node, opline->op2);
6098 if (value_ast->kind == ZEND_AST_ARRAY) {
6099 zend_compile_list_assign(NULL, value_ast, &value_node, value_ast->attr);
6100 } else if (by_ref) {
6101 zend_emit_assign_ref_znode(value_ast, &value_node);
6102 } else {
6103 zend_emit_assign_znode(value_ast, &value_node);
6104 }
6105 }
6106
6107 if (key_ast) {
6108 opline = &CG(active_op_array)->opcodes[opnum_fetch];
6109 zend_make_tmp_result(&key_node, opline);
6110 zend_emit_assign_znode(key_ast, &key_node);
6111 }
6112
6113 zend_compile_stmt(stmt_ast);
6114
6115 /* Place JMP and FE_FREE on the line where foreach starts. It would be
6116 * better to use the end line, but this information is not available
6117 * currently. */
6118 CG(zend_lineno) = ast->lineno;
6119 zend_emit_jump(opnum_fetch);
6120
6121 opline = &CG(active_op_array)->opcodes[opnum_reset];
6122 opline->op2.opline_num = get_next_op_number();
6123
6124 opline = &CG(active_op_array)->opcodes[opnum_fetch];
6125 opline->extended_value = get_next_op_number();
6126
6127 zend_end_loop(opnum_fetch, &reset_node);
6128
6129 opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL);
6130 }
6131 /* }}} */
6132
zend_compile_if(zend_ast * ast)6133 static void zend_compile_if(zend_ast *ast) /* {{{ */
6134 {
6135 zend_ast_list *list = zend_ast_get_list(ast);
6136 uint32_t i;
6137 uint32_t *jmp_opnums = NULL;
6138
6139 if (list->children > 1) {
6140 jmp_opnums = safe_emalloc(sizeof(uint32_t), list->children - 1, 0);
6141 }
6142
6143 for (i = 0; i < list->children; ++i) {
6144 zend_ast *elem_ast = list->child[i];
6145 zend_ast *cond_ast = elem_ast->child[0];
6146 zend_ast *stmt_ast = elem_ast->child[1];
6147
6148 if (cond_ast) {
6149 znode cond_node;
6150 uint32_t opnum_jmpz;
6151
6152 if (i > 0) {
6153 CG(zend_lineno) = cond_ast->lineno;
6154 zend_do_extended_stmt();
6155 }
6156
6157 zend_compile_expr(&cond_node, cond_ast);
6158 opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0);
6159
6160 zend_compile_stmt(stmt_ast);
6161
6162 if (i != list->children - 1) {
6163 /* Set the lineno of JMP to the position of the if keyword, as we don't want to
6164 * report the last line in the if branch as covered if it hasn't actually executed. */
6165 CG(zend_lineno) = elem_ast->lineno;
6166 jmp_opnums[i] = zend_emit_jump(0);
6167 }
6168 zend_update_jump_target_to_next(opnum_jmpz);
6169 } else {
6170 /* "else" can only occur as last element. */
6171 ZEND_ASSERT(i == list->children - 1);
6172 zend_compile_stmt(stmt_ast);
6173 }
6174 }
6175
6176 if (list->children > 1) {
6177 for (i = 0; i < list->children - 1; ++i) {
6178 zend_update_jump_target_to_next(jmp_opnums[i]);
6179 }
6180 efree(jmp_opnums);
6181 }
6182 }
6183 /* }}} */
6184
determine_switch_jumptable_type(zend_ast_list * cases)6185 static uint8_t determine_switch_jumptable_type(zend_ast_list *cases) {
6186 uint32_t i;
6187 uint8_t common_type = IS_UNDEF;
6188 for (i = 0; i < cases->children; i++) {
6189 zend_ast *case_ast = cases->child[i];
6190 zend_ast **cond_ast = &case_ast->child[0];
6191 zval *cond_zv;
6192 if (!case_ast->child[0]) {
6193 /* Skip default clause */
6194 continue;
6195 }
6196
6197 zend_eval_const_expr(cond_ast);
6198 if ((*cond_ast)->kind != ZEND_AST_ZVAL) {
6199 /* Non-constant case */
6200 return IS_UNDEF;
6201 }
6202
6203 cond_zv = zend_ast_get_zval(case_ast->child[0]);
6204 if (Z_TYPE_P(cond_zv) != IS_LONG && Z_TYPE_P(cond_zv) != IS_STRING) {
6205 /* We only optimize switched on integers and strings */
6206 return IS_UNDEF;
6207 }
6208
6209 if (common_type == IS_UNDEF) {
6210 common_type = Z_TYPE_P(cond_zv);
6211 } else if (common_type != Z_TYPE_P(cond_zv)) {
6212 /* Non-uniform case types */
6213 return IS_UNDEF;
6214 }
6215
6216 if (Z_TYPE_P(cond_zv) == IS_STRING
6217 && is_numeric_string(Z_STRVAL_P(cond_zv), Z_STRLEN_P(cond_zv), NULL, NULL, 0)) {
6218 /* Numeric strings cannot be compared with a simple hash lookup */
6219 return IS_UNDEF;
6220 }
6221 }
6222
6223 return common_type;
6224 }
6225
should_use_jumptable(zend_ast_list * cases,uint8_t jumptable_type)6226 static bool should_use_jumptable(zend_ast_list *cases, uint8_t jumptable_type) {
6227 if (CG(compiler_options) & ZEND_COMPILE_NO_JUMPTABLES) {
6228 return 0;
6229 }
6230
6231 /* Thresholds are chosen based on when the average switch time for equidistributed
6232 * input becomes smaller when using the jumptable optimization. */
6233 if (jumptable_type == IS_LONG) {
6234 return cases->children >= 5;
6235 } else {
6236 ZEND_ASSERT(jumptable_type == IS_STRING);
6237 return cases->children >= 2;
6238 }
6239 }
6240
zend_compile_switch(zend_ast * ast)6241 static void zend_compile_switch(zend_ast *ast) /* {{{ */
6242 {
6243 zend_ast *expr_ast = ast->child[0];
6244 zend_ast_list *cases = zend_ast_get_list(ast->child[1]);
6245
6246 uint32_t i;
6247 bool has_default_case = 0;
6248
6249 znode expr_node, case_node;
6250 zend_op *opline;
6251 uint32_t *jmpnz_opnums, opnum_default_jmp, opnum_switch = (uint32_t)-1;
6252 uint8_t jumptable_type;
6253 HashTable *jumptable = NULL;
6254
6255 zend_compile_expr(&expr_node, expr_ast);
6256
6257 zend_begin_loop(ZEND_FREE, &expr_node, 1);
6258
6259 case_node.op_type = IS_TMP_VAR;
6260 case_node.u.op.var = get_temporary_variable();
6261
6262 jumptable_type = determine_switch_jumptable_type(cases);
6263 if (jumptable_type != IS_UNDEF && should_use_jumptable(cases, jumptable_type)) {
6264 znode jumptable_op;
6265
6266 ALLOC_HASHTABLE(jumptable);
6267 zend_hash_init(jumptable, cases->children, NULL, NULL, 0);
6268 jumptable_op.op_type = IS_CONST;
6269 ZVAL_ARR(&jumptable_op.u.constant, jumptable);
6270
6271 opline = zend_emit_op(NULL,
6272 jumptable_type == IS_LONG ? ZEND_SWITCH_LONG : ZEND_SWITCH_STRING,
6273 &expr_node, &jumptable_op);
6274 if (opline->op1_type == IS_CONST) {
6275 Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
6276 }
6277 opnum_switch = opline - CG(active_op_array)->opcodes;
6278 }
6279
6280 jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
6281 for (i = 0; i < cases->children; ++i) {
6282 zend_ast *case_ast = cases->child[i];
6283 zend_ast *cond_ast = case_ast->child[0];
6284 znode cond_node;
6285
6286 if (!cond_ast) {
6287 if (has_default_case) {
6288 CG(zend_lineno) = case_ast->lineno;
6289 zend_error_noreturn(E_COMPILE_ERROR,
6290 "Switch statements may only contain one default clause");
6291 }
6292 has_default_case = 1;
6293 continue;
6294 }
6295
6296 zend_compile_expr(&cond_node, cond_ast);
6297
6298 if (expr_node.op_type == IS_CONST
6299 && Z_TYPE(expr_node.u.constant) == IS_FALSE) {
6300 jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0);
6301 } else if (expr_node.op_type == IS_CONST
6302 && Z_TYPE(expr_node.u.constant) == IS_TRUE) {
6303 jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, 0);
6304 } else {
6305 opline = zend_emit_op(NULL,
6306 (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) ? ZEND_CASE : ZEND_IS_EQUAL,
6307 &expr_node, &cond_node);
6308 SET_NODE(opline->result, &case_node);
6309 if (opline->op1_type == IS_CONST) {
6310 Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
6311 }
6312
6313 jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0);
6314 }
6315 }
6316
6317 opnum_default_jmp = zend_emit_jump(0);
6318
6319 for (i = 0; i < cases->children; ++i) {
6320 zend_ast *case_ast = cases->child[i];
6321 zend_ast *cond_ast = case_ast->child[0];
6322 zend_ast *stmt_ast = case_ast->child[1];
6323
6324 if (cond_ast) {
6325 zend_update_jump_target_to_next(jmpnz_opnums[i]);
6326
6327 if (jumptable) {
6328 zval *cond_zv = zend_ast_get_zval(cond_ast);
6329 zval jmp_target;
6330 ZVAL_LONG(&jmp_target, get_next_op_number());
6331
6332 ZEND_ASSERT(Z_TYPE_P(cond_zv) == jumptable_type);
6333 if (Z_TYPE_P(cond_zv) == IS_LONG) {
6334 zend_hash_index_add(jumptable, Z_LVAL_P(cond_zv), &jmp_target);
6335 } else {
6336 ZEND_ASSERT(Z_TYPE_P(cond_zv) == IS_STRING);
6337 zend_hash_add(jumptable, Z_STR_P(cond_zv), &jmp_target);
6338 }
6339 }
6340 } else {
6341 zend_update_jump_target_to_next(opnum_default_jmp);
6342
6343 if (jumptable) {
6344 ZEND_ASSERT(opnum_switch != (uint32_t)-1);
6345 opline = &CG(active_op_array)->opcodes[opnum_switch];
6346 opline->extended_value = get_next_op_number();
6347 }
6348 }
6349
6350 zend_compile_stmt(stmt_ast);
6351 }
6352
6353 if (!has_default_case) {
6354 zend_update_jump_target_to_next(opnum_default_jmp);
6355
6356 if (jumptable) {
6357 opline = &CG(active_op_array)->opcodes[opnum_switch];
6358 opline->extended_value = get_next_op_number();
6359 }
6360 }
6361
6362 zend_end_loop(get_next_op_number(), &expr_node);
6363
6364 if (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) {
6365 opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
6366 opline->extended_value = ZEND_FREE_SWITCH;
6367 } else if (expr_node.op_type == IS_CONST) {
6368 zval_ptr_dtor_nogc(&expr_node.u.constant);
6369 }
6370
6371 efree(jmpnz_opnums);
6372 }
6373 /* }}} */
6374
count_match_conds(zend_ast_list * arms)6375 static uint32_t count_match_conds(zend_ast_list *arms)
6376 {
6377 uint32_t num_conds = 0;
6378
6379 for (uint32_t i = 0; i < arms->children; i++) {
6380 zend_ast *arm_ast = arms->child[i];
6381 if (arm_ast->child[0] == NULL) {
6382 continue;
6383 }
6384
6385 zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
6386 num_conds += conds->children;
6387 }
6388
6389 return num_conds;
6390 }
6391
can_match_use_jumptable(zend_ast_list * arms)6392 static bool can_match_use_jumptable(zend_ast_list *arms) {
6393 for (uint32_t i = 0; i < arms->children; i++) {
6394 zend_ast *arm_ast = arms->child[i];
6395 if (!arm_ast->child[0]) {
6396 /* Skip default arm */
6397 continue;
6398 }
6399
6400 zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
6401 for (uint32_t j = 0; j < conds->children; j++) {
6402 zend_ast **cond_ast = &conds->child[j];
6403
6404 zend_eval_const_expr(cond_ast);
6405 if ((*cond_ast)->kind != ZEND_AST_ZVAL) {
6406 return 0;
6407 }
6408
6409 zval *cond_zv = zend_ast_get_zval(*cond_ast);
6410 if (Z_TYPE_P(cond_zv) != IS_LONG && Z_TYPE_P(cond_zv) != IS_STRING) {
6411 return 0;
6412 }
6413 }
6414 }
6415
6416 return 1;
6417 }
6418
zend_compile_match(znode * result,zend_ast * ast)6419 static void zend_compile_match(znode *result, zend_ast *ast)
6420 {
6421 zend_ast *expr_ast = ast->child[0];
6422 zend_ast_list *arms = zend_ast_get_list(ast->child[1]);
6423 bool has_default_arm = 0;
6424 uint32_t opnum_match = (uint32_t)-1;
6425
6426 znode expr_node;
6427 zend_compile_expr(&expr_node, expr_ast);
6428
6429 znode case_node;
6430 case_node.op_type = IS_TMP_VAR;
6431 case_node.u.op.var = get_temporary_variable();
6432
6433 uint32_t num_conds = count_match_conds(arms);
6434 uint8_t can_use_jumptable = can_match_use_jumptable(arms);
6435 bool uses_jumptable = can_use_jumptable && num_conds >= 2;
6436 HashTable *jumptable = NULL;
6437 uint32_t *jmpnz_opnums = NULL;
6438
6439 for (uint32_t i = 0; i < arms->children; ++i) {
6440 zend_ast *arm_ast = arms->child[i];
6441
6442 if (!arm_ast->child[0]) {
6443 if (has_default_arm) {
6444 CG(zend_lineno) = arm_ast->lineno;
6445 zend_error_noreturn(E_COMPILE_ERROR,
6446 "Match expressions may only contain one default arm");
6447 }
6448 has_default_arm = 1;
6449 }
6450 }
6451
6452 if (uses_jumptable) {
6453 znode jumptable_op;
6454
6455 ALLOC_HASHTABLE(jumptable);
6456 zend_hash_init(jumptable, num_conds, NULL, NULL, 0);
6457 jumptable_op.op_type = IS_CONST;
6458 ZVAL_ARR(&jumptable_op.u.constant, jumptable);
6459
6460 zend_op *opline = zend_emit_op(NULL, ZEND_MATCH, &expr_node, &jumptable_op);
6461 if (opline->op1_type == IS_CONST) {
6462 Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
6463 }
6464 opnum_match = opline - CG(active_op_array)->opcodes;
6465 } else {
6466 jmpnz_opnums = safe_emalloc(sizeof(uint32_t), num_conds, 0);
6467 uint32_t cond_count = 0;
6468 for (uint32_t i = 0; i < arms->children; ++i) {
6469 zend_ast *arm_ast = arms->child[i];
6470
6471 if (!arm_ast->child[0]) {
6472 continue;
6473 }
6474
6475 zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
6476 for (uint32_t j = 0; j < conds->children; j++) {
6477 zend_ast *cond_ast = conds->child[j];
6478
6479 znode cond_node;
6480 zend_compile_expr(&cond_node, cond_ast);
6481
6482 uint32_t opcode = (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) ? ZEND_CASE_STRICT : ZEND_IS_IDENTICAL;
6483 zend_op *opline = zend_emit_op(NULL, opcode, &expr_node, &cond_node);
6484 SET_NODE(opline->result, &case_node);
6485 if (opline->op1_type == IS_CONST) {
6486 Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
6487 }
6488
6489 jmpnz_opnums[cond_count] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0);
6490
6491 cond_count++;
6492 }
6493 }
6494 }
6495
6496 uint32_t opnum_default_jmp = 0;
6497 if (!uses_jumptable) {
6498 opnum_default_jmp = zend_emit_jump(0);
6499 }
6500
6501 bool is_first_case = 1;
6502 uint32_t cond_count = 0;
6503 uint32_t *jmp_end_opnums = safe_emalloc(sizeof(uint32_t), arms->children, 0);
6504
6505 // The generated default arm is emitted first to avoid live range issues where the tmpvar
6506 // for the arm result is freed even though it has not been initialized yet.
6507 if (!has_default_arm) {
6508 if (!uses_jumptable) {
6509 zend_update_jump_target_to_next(opnum_default_jmp);
6510 }
6511
6512 if (jumptable) {
6513 zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
6514 opline->extended_value = get_next_op_number();
6515 }
6516
6517 zend_op *opline = zend_emit_op(NULL, ZEND_MATCH_ERROR, &expr_node, NULL);
6518 if (opline->op1_type == IS_CONST) {
6519 Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
6520 }
6521 if (arms->children == 0) {
6522 /* Mark this as an "expression throw" for opcache. */
6523 opline->extended_value = ZEND_THROW_IS_EXPR;
6524 }
6525 }
6526
6527 for (uint32_t i = 0; i < arms->children; ++i) {
6528 zend_ast *arm_ast = arms->child[i];
6529 zend_ast *body_ast = arm_ast->child[1];
6530
6531 if (arm_ast->child[0] != NULL) {
6532 zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
6533
6534 for (uint32_t j = 0; j < conds->children; j++) {
6535 zend_ast *cond_ast = conds->child[j];
6536
6537 if (jmpnz_opnums != NULL) {
6538 zend_update_jump_target_to_next(jmpnz_opnums[cond_count]);
6539 }
6540
6541 if (jumptable) {
6542 zval *cond_zv = zend_ast_get_zval(cond_ast);
6543 zval jmp_target;
6544 ZVAL_LONG(&jmp_target, get_next_op_number());
6545
6546 if (Z_TYPE_P(cond_zv) == IS_LONG) {
6547 zend_hash_index_add(jumptable, Z_LVAL_P(cond_zv), &jmp_target);
6548 } else {
6549 ZEND_ASSERT(Z_TYPE_P(cond_zv) == IS_STRING);
6550 zend_hash_add(jumptable, Z_STR_P(cond_zv), &jmp_target);
6551 }
6552 }
6553
6554 cond_count++;
6555 }
6556 } else {
6557 if (!uses_jumptable) {
6558 zend_update_jump_target_to_next(opnum_default_jmp);
6559 }
6560
6561 if (jumptable) {
6562 ZEND_ASSERT(opnum_match != (uint32_t)-1);
6563 zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
6564 opline->extended_value = get_next_op_number();
6565 }
6566 }
6567
6568 znode body_node;
6569 zend_compile_expr(&body_node, body_ast);
6570
6571 if (is_first_case) {
6572 zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &body_node, NULL);
6573 is_first_case = 0;
6574 } else {
6575 zend_op *opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN, &body_node, NULL);
6576 SET_NODE(opline_qm_assign->result, result);
6577 }
6578
6579 jmp_end_opnums[i] = zend_emit_jump(0);
6580 }
6581
6582 // Initialize result in case there is no arm
6583 if (arms->children == 0) {
6584 result->op_type = IS_CONST;
6585 ZVAL_NULL(&result->u.constant);
6586 }
6587
6588 for (uint32_t i = 0; i < arms->children; ++i) {
6589 zend_update_jump_target_to_next(jmp_end_opnums[i]);
6590 }
6591
6592 if (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) {
6593 zend_op *opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
6594 opline->extended_value = ZEND_FREE_SWITCH;
6595 } else if (expr_node.op_type == IS_CONST) {
6596 zval_ptr_dtor_nogc(&expr_node.u.constant);
6597 }
6598
6599 if (jmpnz_opnums != NULL) {
6600 efree(jmpnz_opnums);
6601 }
6602 efree(jmp_end_opnums);
6603 }
6604
zend_compile_try(zend_ast * ast)6605 static void zend_compile_try(zend_ast *ast) /* {{{ */
6606 {
6607 zend_ast *try_ast = ast->child[0];
6608 zend_ast_list *catches = zend_ast_get_list(ast->child[1]);
6609 zend_ast *finally_ast = ast->child[2];
6610
6611 uint32_t i, j;
6612 zend_op *opline;
6613 uint32_t try_catch_offset;
6614 uint32_t *jmp_opnums = safe_emalloc(sizeof(uint32_t), catches->children, 0);
6615 uint32_t orig_fast_call_var = CG(context).fast_call_var;
6616 uint32_t orig_try_catch_offset = CG(context).try_catch_offset;
6617
6618 if (catches->children == 0 && !finally_ast) {
6619 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use try without catch or finally");
6620 }
6621
6622 /* label: try { } must not be equal to try { label: } */
6623 if (CG(context).labels) {
6624 zend_label *label;
6625 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(CG(context).labels, label) {
6626 if (label->opline_num == get_next_op_number()) {
6627 zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
6628 }
6629 break;
6630 } ZEND_HASH_FOREACH_END();
6631 }
6632
6633 try_catch_offset = zend_add_try_element(get_next_op_number());
6634
6635 if (finally_ast) {
6636 zend_loop_var fast_call;
6637 if (!(CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
6638 CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_FINALLY_BLOCK;
6639 }
6640 CG(context).fast_call_var = get_temporary_variable();
6641
6642 /* Push FAST_CALL on unwind stack */
6643 fast_call.opcode = ZEND_FAST_CALL;
6644 fast_call.var_type = IS_TMP_VAR;
6645 fast_call.var_num = CG(context).fast_call_var;
6646 fast_call.try_catch_offset = try_catch_offset;
6647 zend_stack_push(&CG(loop_var_stack), &fast_call);
6648 }
6649
6650 CG(context).try_catch_offset = try_catch_offset;
6651
6652 zend_compile_stmt(try_ast);
6653
6654 if (catches->children != 0) {
6655 jmp_opnums[0] = zend_emit_jump(0);
6656 }
6657
6658 for (i = 0; i < catches->children; ++i) {
6659 zend_ast *catch_ast = catches->child[i];
6660 zend_ast_list *classes = zend_ast_get_list(catch_ast->child[0]);
6661 zend_ast *var_ast = catch_ast->child[1];
6662 zend_ast *stmt_ast = catch_ast->child[2];
6663 zend_string *var_name = var_ast ? zval_make_interned_string(zend_ast_get_zval(var_ast)) : NULL;
6664 bool is_last_catch = (i + 1 == catches->children);
6665
6666 uint32_t *jmp_multicatch = safe_emalloc(sizeof(uint32_t), classes->children - 1, 0);
6667 uint32_t opnum_catch = (uint32_t)-1;
6668
6669 CG(zend_lineno) = catch_ast->lineno;
6670
6671 for (j = 0; j < classes->children; j++) {
6672 zend_ast *class_ast = classes->child[j];
6673 bool is_last_class = (j + 1 == classes->children);
6674
6675 if (!zend_is_const_default_class_ref(class_ast)) {
6676 zend_error_noreturn(E_COMPILE_ERROR, "Bad class name in the catch statement");
6677 }
6678
6679 opnum_catch = get_next_op_number();
6680 if (i == 0 && j == 0) {
6681 CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = opnum_catch;
6682 }
6683
6684 opline = get_next_op();
6685 opline->opcode = ZEND_CATCH;
6686 opline->op1_type = IS_CONST;
6687 opline->op1.constant = zend_add_class_name_literal(
6688 zend_resolve_class_name_ast(class_ast));
6689 opline->extended_value = zend_alloc_cache_slot();
6690
6691 if (var_name && zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
6692 zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
6693 }
6694
6695 opline->result_type = var_name ? IS_CV : IS_UNUSED;
6696 opline->result.var = var_name ? lookup_cv(var_name) : -1;
6697
6698 if (is_last_catch && is_last_class) {
6699 opline->extended_value |= ZEND_LAST_CATCH;
6700 }
6701
6702 if (!is_last_class) {
6703 jmp_multicatch[j] = zend_emit_jump(0);
6704 opline = &CG(active_op_array)->opcodes[opnum_catch];
6705 opline->op2.opline_num = get_next_op_number();
6706 }
6707 }
6708
6709 for (j = 0; j < classes->children - 1; j++) {
6710 zend_update_jump_target_to_next(jmp_multicatch[j]);
6711 }
6712
6713 efree(jmp_multicatch);
6714
6715 zend_compile_stmt(stmt_ast);
6716
6717 if (!is_last_catch) {
6718 jmp_opnums[i + 1] = zend_emit_jump(0);
6719 }
6720
6721 ZEND_ASSERT(opnum_catch != (uint32_t)-1 && "Should have at least one class");
6722 opline = &CG(active_op_array)->opcodes[opnum_catch];
6723 if (!is_last_catch) {
6724 opline->op2.opline_num = get_next_op_number();
6725 }
6726 }
6727
6728 for (i = 0; i < catches->children; ++i) {
6729 zend_update_jump_target_to_next(jmp_opnums[i]);
6730 }
6731
6732 if (finally_ast) {
6733 zend_loop_var discard_exception;
6734 uint32_t opnum_jmp = get_next_op_number() + 1;
6735
6736 /* Pop FAST_CALL from unwind stack */
6737 zend_stack_del_top(&CG(loop_var_stack));
6738
6739 /* Push DISCARD_EXCEPTION on unwind stack */
6740 discard_exception.opcode = ZEND_DISCARD_EXCEPTION;
6741 discard_exception.var_type = IS_TMP_VAR;
6742 discard_exception.var_num = CG(context).fast_call_var;
6743 zend_stack_push(&CG(loop_var_stack), &discard_exception);
6744
6745 CG(zend_lineno) = finally_ast->lineno;
6746
6747 opline = zend_emit_op(NULL, ZEND_FAST_CALL, NULL, NULL);
6748 opline->op1.num = try_catch_offset;
6749 opline->result_type = IS_TMP_VAR;
6750 opline->result.var = CG(context).fast_call_var;
6751
6752 zend_emit_op(NULL, ZEND_JMP, NULL, NULL);
6753
6754 zend_compile_stmt(finally_ast);
6755
6756 CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = opnum_jmp + 1;
6757 CG(active_op_array)->try_catch_array[try_catch_offset].finally_end
6758 = get_next_op_number();
6759
6760 opline = zend_emit_op(NULL, ZEND_FAST_RET, NULL, NULL);
6761 opline->op1_type = IS_TMP_VAR;
6762 opline->op1.var = CG(context).fast_call_var;
6763 opline->op2.num = orig_try_catch_offset;
6764
6765 zend_update_jump_target_to_next(opnum_jmp);
6766
6767 CG(context).fast_call_var = orig_fast_call_var;
6768
6769 /* Pop DISCARD_EXCEPTION from unwind stack */
6770 zend_stack_del_top(&CG(loop_var_stack));
6771 }
6772
6773 CG(context).try_catch_offset = orig_try_catch_offset;
6774
6775 efree(jmp_opnums);
6776 }
6777 /* }}} */
6778
6779 /* Encoding declarations must already be handled during parsing */
zend_handle_encoding_declaration(zend_ast * ast)6780 bool zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */
6781 {
6782 zend_ast_list *declares = zend_ast_get_list(ast);
6783 uint32_t i;
6784 for (i = 0; i < declares->children; ++i) {
6785 zend_ast *declare_ast = declares->child[i];
6786 zend_ast *name_ast = declare_ast->child[0];
6787 zend_ast *value_ast = declare_ast->child[1];
6788 zend_string *name = zend_ast_get_str(name_ast);
6789
6790 if (zend_string_equals_literal_ci(name, "encoding")) {
6791 if (value_ast->kind != ZEND_AST_ZVAL) {
6792 zend_throw_exception(zend_ce_compile_error, "Encoding must be a literal", 0);
6793 return 0;
6794 }
6795
6796 if (CG(multibyte)) {
6797 zend_string *encoding_name = zval_get_string(zend_ast_get_zval(value_ast));
6798
6799 const zend_encoding *new_encoding, *old_encoding;
6800 zend_encoding_filter old_input_filter;
6801
6802 CG(encoding_declared) = 1;
6803
6804 new_encoding = zend_multibyte_fetch_encoding(ZSTR_VAL(encoding_name));
6805 if (!new_encoding) {
6806 zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", ZSTR_VAL(encoding_name));
6807 } else {
6808 old_input_filter = LANG_SCNG(input_filter);
6809 old_encoding = LANG_SCNG(script_encoding);
6810 zend_multibyte_set_filter(new_encoding);
6811
6812 /* need to re-scan if input filter changed */
6813 if (old_input_filter != LANG_SCNG(input_filter) ||
6814 (old_input_filter && new_encoding != old_encoding)) {
6815 zend_multibyte_yyinput_again(old_input_filter, old_encoding);
6816 }
6817 }
6818
6819 zend_string_release_ex(encoding_name, 0);
6820 } else {
6821 zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because "
6822 "Zend multibyte feature is turned off by settings");
6823 }
6824 }
6825 }
6826
6827 return 1;
6828 }
6829 /* }}} */
6830
6831 /* Check whether this is the first statement, not counting declares. */
zend_is_first_statement(zend_ast * ast,bool allow_nop)6832 static zend_result zend_is_first_statement(zend_ast *ast, bool allow_nop) /* {{{ */
6833 {
6834 uint32_t i = 0;
6835 zend_ast_list *file_ast = zend_ast_get_list(CG(ast));
6836
6837 while (i < file_ast->children) {
6838 if (file_ast->child[i] == ast) {
6839 return SUCCESS;
6840 } else if (file_ast->child[i] == NULL) {
6841 if (!allow_nop) {
6842 return FAILURE;
6843 }
6844 } else if (file_ast->child[i]->kind != ZEND_AST_DECLARE) {
6845 return FAILURE;
6846 }
6847 i++;
6848 }
6849 return FAILURE;
6850 }
6851 /* }}} */
6852
zend_compile_declare(zend_ast * ast)6853 static void zend_compile_declare(zend_ast *ast) /* {{{ */
6854 {
6855 zend_ast_list *declares = zend_ast_get_list(ast->child[0]);
6856 zend_ast *stmt_ast = ast->child[1];
6857 zend_declarables orig_declarables = FC(declarables);
6858 uint32_t i;
6859
6860 for (i = 0; i < declares->children; ++i) {
6861 zend_ast *declare_ast = declares->child[i];
6862 zend_ast *name_ast = declare_ast->child[0];
6863 zend_ast **value_ast_ptr = &declare_ast->child[1];
6864 zend_string *name = zend_ast_get_str(name_ast);
6865
6866 if ((*value_ast_ptr)->kind != ZEND_AST_ZVAL) {
6867 zend_error_noreturn(E_COMPILE_ERROR, "declare(%s) value must be a literal", ZSTR_VAL(name));
6868 }
6869
6870 if (zend_string_equals_literal_ci(name, "ticks")) {
6871 zval value_zv;
6872 zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ false);
6873 FC(declarables).ticks = zval_get_long(&value_zv);
6874 zval_ptr_dtor_nogc(&value_zv);
6875 } else if (zend_string_equals_literal_ci(name, "encoding")) {
6876
6877 if (FAILURE == zend_is_first_statement(ast, /* allow_nop */ 0)) {
6878 zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be "
6879 "the very first statement in the script");
6880 }
6881 } else if (zend_string_equals_literal_ci(name, "strict_types")) {
6882 zval value_zv;
6883
6884 if (FAILURE == zend_is_first_statement(ast, /* allow_nop */ 0)) {
6885 zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must be "
6886 "the very first statement in the script");
6887 }
6888
6889 if (ast->child[1] != NULL) {
6890 zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must not "
6891 "use block mode");
6892 }
6893
6894 zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ false);
6895
6896 if (Z_TYPE(value_zv) != IS_LONG || (Z_LVAL(value_zv) != 0 && Z_LVAL(value_zv) != 1)) {
6897 zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must have 0 or 1 as its value");
6898 }
6899
6900 if (Z_LVAL(value_zv) == 1) {
6901 CG(active_op_array)->fn_flags |= ZEND_ACC_STRICT_TYPES;
6902 }
6903
6904 } else {
6905 zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", ZSTR_VAL(name));
6906 }
6907 }
6908
6909 if (stmt_ast) {
6910 zend_compile_stmt(stmt_ast);
6911
6912 FC(declarables) = orig_declarables;
6913 }
6914 }
6915 /* }}} */
6916
zend_compile_stmt_list(zend_ast * ast)6917 static void zend_compile_stmt_list(zend_ast *ast) /* {{{ */
6918 {
6919 zend_ast_list *list = zend_ast_get_list(ast);
6920 uint32_t i;
6921 for (i = 0; i < list->children; ++i) {
6922 zend_compile_stmt(list->child[i]);
6923 }
6924 }
6925 /* }}} */
6926
zend_set_function_arg_flags(zend_function * func)6927 ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */
6928 {
6929 uint32_t i, n;
6930
6931 func->common.arg_flags[0] = 0;
6932 func->common.arg_flags[1] = 0;
6933 func->common.arg_flags[2] = 0;
6934 if (func->common.arg_info) {
6935 n = MIN(func->common.num_args, MAX_ARG_FLAG_NUM);
6936 i = 0;
6937 while (i < n) {
6938 ZEND_SET_ARG_FLAG(func, i + 1, ZEND_ARG_SEND_MODE(&func->common.arg_info[i]));
6939 i++;
6940 }
6941 if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_VARIADIC) && ZEND_ARG_SEND_MODE(&func->common.arg_info[i]))) {
6942 uint32_t pass_by_reference = ZEND_ARG_SEND_MODE(&func->common.arg_info[i]);
6943 while (i < MAX_ARG_FLAG_NUM) {
6944 ZEND_SET_ARG_FLAG(func, i + 1, pass_by_reference);
6945 i++;
6946 }
6947 }
6948 }
6949 }
6950 /* }}} */
6951
zend_compile_single_typename(zend_ast * ast)6952 static zend_type zend_compile_single_typename(zend_ast *ast)
6953 {
6954 ZEND_ASSERT(!(ast->attr & ZEND_TYPE_NULLABLE));
6955 if (ast->kind == ZEND_AST_TYPE) {
6956 if (ast->attr == IS_STATIC && !CG(active_class_entry) && zend_is_scope_known()) {
6957 zend_error_noreturn(E_COMPILE_ERROR,
6958 "Cannot use \"static\" when no class scope is active");
6959 }
6960
6961 return (zend_type) ZEND_TYPE_INIT_CODE(ast->attr, 0, 0);
6962 } else {
6963 zend_string *class_name = zend_ast_get_str(ast);
6964 uint8_t type_code = zend_lookup_builtin_type_by_name(class_name);
6965
6966 if (type_code != 0) {
6967 if ((ast->attr & ZEND_NAME_NOT_FQ) != ZEND_NAME_NOT_FQ) {
6968 zend_error_noreturn(E_COMPILE_ERROR,
6969 "Type declaration '%s' must be unqualified",
6970 ZSTR_VAL(zend_string_tolower(class_name)));
6971 }
6972
6973 /* Transform iterable into a type union alias */
6974 if (type_code == IS_ITERABLE) {
6975 /* Set iterable bit for BC compat during Reflection and string representation of type */
6976 zend_type iterable = (zend_type) ZEND_TYPE_INIT_CLASS_MASK(ZSTR_KNOWN(ZEND_STR_TRAVERSABLE),
6977 (MAY_BE_ARRAY|_ZEND_TYPE_ITERABLE_BIT));
6978 return iterable;
6979 }
6980
6981 return (zend_type) ZEND_TYPE_INIT_CODE(type_code, 0, 0);
6982 } else {
6983 const char *correct_name;
6984 zend_string *orig_name = zend_ast_get_str(ast);
6985 uint32_t fetch_type = zend_get_class_fetch_type_ast(ast);
6986 if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
6987 class_name = zend_resolve_class_name_ast(ast);
6988 zend_assert_valid_class_name(class_name, "a type name");
6989 } else {
6990 zend_ensure_valid_class_fetch_type(fetch_type);
6991 zend_string_addref(class_name);
6992 }
6993
6994 if (ast->attr == ZEND_NAME_NOT_FQ
6995 && zend_is_confusable_type(orig_name, &correct_name)
6996 && zend_is_not_imported(orig_name)) {
6997 const char *extra =
6998 FC(current_namespace) ? " or import the class with \"use\"" : "";
6999 if (correct_name) {
7000 zend_error(E_COMPILE_WARNING,
7001 "\"%s\" will be interpreted as a class name. Did you mean \"%s\"? "
7002 "Write \"\\%s\"%s to suppress this warning",
7003 ZSTR_VAL(orig_name), correct_name, ZSTR_VAL(class_name), extra);
7004 } else {
7005 zend_error(E_COMPILE_WARNING,
7006 "\"%s\" is not a supported builtin type "
7007 "and will be interpreted as a class name. "
7008 "Write \"\\%s\"%s to suppress this warning",
7009 ZSTR_VAL(orig_name), ZSTR_VAL(class_name), extra);
7010 }
7011 }
7012
7013 class_name = zend_new_interned_string(class_name);
7014 zend_alloc_ce_cache(class_name);
7015 return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, 0, 0);
7016 }
7017 }
7018 }
7019
zend_are_intersection_types_redundant(zend_type left_type,zend_type right_type)7020 static void zend_are_intersection_types_redundant(zend_type left_type, zend_type right_type)
7021 {
7022 ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(left_type));
7023 ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(right_type));
7024 zend_type_list *l_type_list = ZEND_TYPE_LIST(left_type);
7025 zend_type_list *r_type_list = ZEND_TYPE_LIST(right_type);
7026 zend_type_list *smaller_type_list, *larger_type_list;
7027 bool flipped = false;
7028
7029 if (r_type_list->num_types < l_type_list->num_types) {
7030 smaller_type_list = r_type_list;
7031 larger_type_list = l_type_list;
7032 flipped = true;
7033 } else {
7034 smaller_type_list = l_type_list;
7035 larger_type_list = r_type_list;
7036 }
7037
7038 unsigned int sum = 0;
7039 zend_type *outer_type;
7040 ZEND_TYPE_LIST_FOREACH(smaller_type_list, outer_type)
7041 zend_type *inner_type;
7042 ZEND_TYPE_LIST_FOREACH(larger_type_list, inner_type)
7043 if (zend_string_equals_ci(ZEND_TYPE_NAME(*inner_type), ZEND_TYPE_NAME(*outer_type))) {
7044 sum++;
7045 break;
7046 }
7047 ZEND_TYPE_LIST_FOREACH_END();
7048 ZEND_TYPE_LIST_FOREACH_END();
7049
7050 if (sum == smaller_type_list->num_types) {
7051 zend_string *smaller_type_str;
7052 zend_string *larger_type_str;
7053 if (flipped) {
7054 smaller_type_str = zend_type_to_string(right_type);
7055 larger_type_str = zend_type_to_string(left_type);
7056 } else {
7057 smaller_type_str = zend_type_to_string(left_type);
7058 larger_type_str = zend_type_to_string(right_type);
7059 }
7060 if (smaller_type_list->num_types == larger_type_list->num_types) {
7061 zend_error_noreturn(E_COMPILE_ERROR, "Type %s is redundant with type %s",
7062 ZSTR_VAL(smaller_type_str), ZSTR_VAL(larger_type_str));
7063 } else {
7064 zend_error_noreturn(E_COMPILE_ERROR, "Type %s is redundant as it is more restrictive than type %s",
7065 ZSTR_VAL(larger_type_str), ZSTR_VAL(smaller_type_str));
7066 }
7067 }
7068 }
7069
zend_is_intersection_type_redundant_by_single_type(zend_type intersection_type,zend_type single_type)7070 static void zend_is_intersection_type_redundant_by_single_type(zend_type intersection_type, zend_type single_type)
7071 {
7072 ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(intersection_type));
7073 ZEND_ASSERT(!ZEND_TYPE_IS_INTERSECTION(single_type));
7074
7075 zend_type *single_intersection_type = NULL;
7076 ZEND_TYPE_FOREACH(intersection_type, single_intersection_type)
7077 if (zend_string_equals_ci(ZEND_TYPE_NAME(*single_intersection_type), ZEND_TYPE_NAME(single_type))) {
7078 zend_string *single_type_str = zend_type_to_string(single_type);
7079 zend_string *complete_type = zend_type_to_string(intersection_type);
7080 zend_error_noreturn(E_COMPILE_ERROR, "Type %s is redundant as it is more restrictive than type %s",
7081 ZSTR_VAL(complete_type), ZSTR_VAL(single_type_str));
7082 }
7083 ZEND_TYPE_FOREACH_END();
7084 }
7085
7086 /* Used by both intersection and union types prior to transforming the type list to a full zend_type */
zend_is_type_list_redundant_by_single_type(zend_type_list * type_list,zend_type type)7087 static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list, zend_type type)
7088 {
7089 ZEND_ASSERT(!ZEND_TYPE_IS_INTERSECTION(type));
7090 for (size_t i = 0; i < type_list->num_types - 1; i++) {
7091 if (ZEND_TYPE_IS_INTERSECTION(type_list->types[i])) {
7092 zend_is_intersection_type_redundant_by_single_type(type_list->types[i], type);
7093 continue;
7094 }
7095 if (zend_string_equals_ci(ZEND_TYPE_NAME(type_list->types[i]), ZEND_TYPE_NAME(type))) {
7096 zend_string *single_type_str = zend_type_to_string(type);
7097 zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
7098 }
7099 }
7100 }
7101
7102 static zend_type zend_compile_typename(zend_ast *ast);
7103
zend_compile_typename_ex(zend_ast * ast,bool force_allow_null,bool * forced_allow_null)7104 static zend_type zend_compile_typename_ex(
7105 zend_ast *ast, bool force_allow_null, bool *forced_allow_null) /* {{{ */
7106 {
7107 bool is_marked_nullable = ast->attr & ZEND_TYPE_NULLABLE;
7108 zend_ast_attr orig_ast_attr = ast->attr;
7109 zend_type type = ZEND_TYPE_INIT_NONE(0);
7110
7111 if (is_marked_nullable) {
7112 ast->attr &= ~ZEND_TYPE_NULLABLE;
7113 }
7114
7115 if (ast->kind == ZEND_AST_TYPE_UNION) {
7116 zend_ast_list *list = zend_ast_get_list(ast);
7117 zend_type_list *type_list;
7118 bool is_composite = false;
7119 bool has_only_iterable_class = true;
7120 ALLOCA_FLAG(use_heap)
7121
7122 type_list = do_alloca(ZEND_TYPE_LIST_SIZE(list->children), use_heap);
7123 type_list->num_types = 0;
7124
7125 for (uint32_t i = 0; i < list->children; i++) {
7126 zend_ast *type_ast = list->child[i];
7127 zend_type single_type;
7128 uint32_t type_mask = ZEND_TYPE_FULL_MASK(type);
7129
7130 if (type_ast->kind == ZEND_AST_TYPE_INTERSECTION) {
7131 has_only_iterable_class = false;
7132 is_composite = true;
7133 /* The first class type can be stored directly as the type ptr payload. */
7134 if (ZEND_TYPE_IS_COMPLEX(type) && !ZEND_TYPE_HAS_LIST(type)) {
7135 /* Switch from single name to name list. */
7136 type_list->num_types = 1;
7137 type_list->types[0] = type;
7138 ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
7139 }
7140 /* Mark type as list type */
7141 ZEND_TYPE_SET_LIST(type, type_list);
7142
7143 single_type = zend_compile_typename(type_ast);
7144 ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(single_type));
7145
7146 type_list->types[type_list->num_types++] = single_type;
7147
7148 /* Check for trivially redundant class types */
7149 for (size_t i = 0; i < type_list->num_types - 1; i++) {
7150 if (ZEND_TYPE_IS_INTERSECTION(type_list->types[i])) {
7151 zend_are_intersection_types_redundant(single_type, type_list->types[i]);
7152 continue;
7153 }
7154 /* Type from type list is a simple type */
7155 zend_is_intersection_type_redundant_by_single_type(single_type, type_list->types[i]);
7156 }
7157 continue;
7158 }
7159
7160 single_type = zend_compile_single_typename(type_ast);
7161 uint32_t single_type_mask = ZEND_TYPE_PURE_MASK(single_type);
7162
7163 if (single_type_mask == MAY_BE_ANY) {
7164 zend_error_noreturn(E_COMPILE_ERROR, "Type mixed can only be used as a standalone type");
7165 }
7166 if (ZEND_TYPE_IS_COMPLEX(single_type) && !ZEND_TYPE_IS_ITERABLE_FALLBACK(single_type)) {
7167 has_only_iterable_class = false;
7168 }
7169
7170 uint32_t type_mask_overlap = ZEND_TYPE_PURE_MASK(type) & single_type_mask;
7171 if (type_mask_overlap) {
7172 zend_type overlap_type = ZEND_TYPE_INIT_MASK(type_mask_overlap);
7173 zend_string *overlap_type_str = zend_type_to_string(overlap_type);
7174 zend_error_noreturn(E_COMPILE_ERROR,
7175 "Duplicate type %s is redundant", ZSTR_VAL(overlap_type_str));
7176 }
7177
7178 if ( ((type_mask & MAY_BE_TRUE) && (single_type_mask == MAY_BE_FALSE))
7179 || ((type_mask & MAY_BE_FALSE) && (single_type_mask == MAY_BE_TRUE)) ) {
7180 zend_error_noreturn(E_COMPILE_ERROR,
7181 "Type contains both true and false, bool must be used instead");
7182 }
7183 ZEND_TYPE_FULL_MASK(type) |= ZEND_TYPE_PURE_MASK(single_type);
7184 ZEND_TYPE_FULL_MASK(single_type) &= ~_ZEND_TYPE_MAY_BE_MASK;
7185
7186 if (ZEND_TYPE_IS_COMPLEX(single_type)) {
7187 if (!ZEND_TYPE_IS_COMPLEX(type) && !is_composite) {
7188 /* The first class type can be stored directly as the type ptr payload. */
7189 ZEND_TYPE_SET_PTR(type, ZEND_TYPE_NAME(single_type));
7190 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_BIT;
7191 } else {
7192 if (type_list->num_types == 0) {
7193 /* Switch from single name to name list. */
7194 type_list->num_types = 1;
7195 type_list->types[0] = type;
7196 ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
7197 ZEND_TYPE_SET_LIST(type, type_list);
7198 }
7199
7200 type_list->types[type_list->num_types++] = single_type;
7201
7202 /* Check for trivially redundant class types */
7203 zend_is_type_list_redundant_by_single_type(type_list, single_type);
7204 }
7205 }
7206 }
7207
7208 if (type_list->num_types) {
7209 zend_type_list *list = zend_arena_alloc(
7210 &CG(arena), ZEND_TYPE_LIST_SIZE(type_list->num_types));
7211 memcpy(list, type_list, ZEND_TYPE_LIST_SIZE(type_list->num_types));
7212 ZEND_TYPE_SET_LIST(type, list);
7213 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_ARENA_BIT;
7214 /* Inform that the type list is a union type */
7215 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_UNION_BIT;
7216 }
7217
7218 free_alloca(type_list, use_heap);
7219
7220 uint32_t type_mask = ZEND_TYPE_FULL_MASK(type);
7221 if ((type_mask & MAY_BE_OBJECT) &&
7222 ((!has_only_iterable_class && ZEND_TYPE_IS_COMPLEX(type)) || (type_mask & MAY_BE_STATIC))) {
7223 zend_string *type_str = zend_type_to_string(type);
7224 zend_error_noreturn(E_COMPILE_ERROR,
7225 "Type %s contains both object and a class type, which is redundant",
7226 ZSTR_VAL(type_str));
7227 }
7228 } else if (ast->kind == ZEND_AST_TYPE_INTERSECTION) {
7229 zend_ast_list *list = zend_ast_get_list(ast);
7230 zend_type_list *type_list;
7231
7232 /* Allocate the type list directly on the arena as it must be a type
7233 * list of the same number of elements as the AST list has children */
7234 type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->children));
7235 type_list->num_types = 0;
7236
7237 ZEND_ASSERT(list->children > 1);
7238
7239 for (uint32_t i = 0; i < list->children; i++) {
7240 zend_ast *type_ast = list->child[i];
7241 zend_type single_type = zend_compile_single_typename(type_ast);
7242
7243 /* An intersection of union types cannot exist so invalidate it
7244 * Currently only can happen with iterable getting canonicalized to Traversable|array */
7245 if (ZEND_TYPE_IS_ITERABLE_FALLBACK(single_type)) {
7246 zend_string *standard_type_str = zend_type_to_string(single_type);
7247 zend_error_noreturn(E_COMPILE_ERROR,
7248 "Type %s cannot be part of an intersection type", ZSTR_VAL(standard_type_str));
7249 zend_string_release_ex(standard_type_str, false);
7250 }
7251 /* An intersection of standard types cannot exist so invalidate it */
7252 if (ZEND_TYPE_IS_ONLY_MASK(single_type)) {
7253 zend_string *standard_type_str = zend_type_to_string(single_type);
7254 zend_error_noreturn(E_COMPILE_ERROR,
7255 "Type %s cannot be part of an intersection type", ZSTR_VAL(standard_type_str));
7256 zend_string_release_ex(standard_type_str, false);
7257 }
7258 /* Check for "self" and "parent" too */
7259 if (zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "self")
7260 || zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "parent")) {
7261 zend_error_noreturn(E_COMPILE_ERROR,
7262 "Type %s cannot be part of an intersection type", ZSTR_VAL(ZEND_TYPE_NAME(single_type)));
7263 }
7264
7265 /* Add type to the type list */
7266 type_list->types[type_list->num_types++] = single_type;
7267
7268 /* Check for trivially redundant class types */
7269 zend_is_type_list_redundant_by_single_type(type_list, single_type);
7270 }
7271
7272 ZEND_ASSERT(list->children == type_list->num_types);
7273
7274 /* An implicitly nullable intersection type needs to be converted to a DNF type */
7275 if (force_allow_null) {
7276 zend_type intersection_type = ZEND_TYPE_INIT_NONE(0);
7277 ZEND_TYPE_SET_LIST(intersection_type, type_list);
7278 ZEND_TYPE_FULL_MASK(intersection_type) |= _ZEND_TYPE_INTERSECTION_BIT;
7279 ZEND_TYPE_FULL_MASK(intersection_type) |= _ZEND_TYPE_ARENA_BIT;
7280
7281 zend_type_list *dnf_type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(1));
7282 dnf_type_list->num_types = 1;
7283 dnf_type_list->types[0] = intersection_type;
7284 ZEND_TYPE_SET_LIST(type, dnf_type_list);
7285 /* Inform that the type list is a DNF type */
7286 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_UNION_BIT;
7287 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_ARENA_BIT;
7288 } else {
7289 ZEND_TYPE_SET_LIST(type, type_list);
7290 /* Inform that the type list is an intersection type */
7291 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_INTERSECTION_BIT;
7292 ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_ARENA_BIT;
7293 }
7294 } else {
7295 type = zend_compile_single_typename(ast);
7296 }
7297
7298 uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
7299
7300 if (type_mask == MAY_BE_ANY && is_marked_nullable) {
7301 zend_error_noreturn(E_COMPILE_ERROR, "Type mixed cannot be marked as nullable since mixed already includes null");
7302 }
7303
7304 if ((type_mask & MAY_BE_NULL) && is_marked_nullable) {
7305 zend_error_noreturn(E_COMPILE_ERROR, "null cannot be marked as nullable");
7306 }
7307
7308 if (force_allow_null && !is_marked_nullable && !(type_mask & MAY_BE_NULL)) {
7309 *forced_allow_null = true;
7310 }
7311
7312 if (is_marked_nullable || force_allow_null) {
7313 ZEND_TYPE_FULL_MASK(type) |= MAY_BE_NULL;
7314 type_mask = ZEND_TYPE_PURE_MASK(type);
7315 }
7316
7317 if ((type_mask & MAY_BE_VOID) && (ZEND_TYPE_IS_COMPLEX(type) || type_mask != MAY_BE_VOID)) {
7318 zend_error_noreturn(E_COMPILE_ERROR, "Void can only be used as a standalone type");
7319 }
7320
7321 if ((type_mask & MAY_BE_NEVER) && (ZEND_TYPE_IS_COMPLEX(type) || type_mask != MAY_BE_NEVER)) {
7322 zend_error_noreturn(E_COMPILE_ERROR, "never can only be used as a standalone type");
7323 }
7324
7325 ast->attr = orig_ast_attr;
7326 return type;
7327 }
7328 /* }}} */
7329
zend_compile_typename(zend_ast * ast)7330 static zend_type zend_compile_typename(zend_ast *ast)
7331 {
7332 bool forced_allow_null;
7333 return zend_compile_typename_ex(ast, false, &forced_allow_null);
7334 }
7335
7336 /* May convert value from int to float. */
zend_is_valid_default_value(zend_type type,zval * value)7337 static bool zend_is_valid_default_value(zend_type type, zval *value)
7338 {
7339 ZEND_ASSERT(ZEND_TYPE_IS_SET(type));
7340 if (ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE_P(value))) {
7341 return 1;
7342 }
7343 if ((ZEND_TYPE_FULL_MASK(type) & MAY_BE_DOUBLE) && Z_TYPE_P(value) == IS_LONG) {
7344 /* Integers are allowed as initializers for floating-point values. */
7345 convert_to_double(value);
7346 return 1;
7347 }
7348 return 0;
7349 }
7350
zend_compile_attributes(HashTable ** attributes,zend_ast * ast,uint32_t offset,uint32_t target,uint32_t promoted)7351 static void zend_compile_attributes(
7352 HashTable **attributes, zend_ast *ast, uint32_t offset, uint32_t target, uint32_t promoted
7353 ) /* {{{ */ {
7354 zend_attribute *attr;
7355 zend_internal_attribute *config;
7356
7357 zend_ast_list *list = zend_ast_get_list(ast);
7358 uint32_t g, i, j;
7359
7360 ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);
7361
7362 for (g = 0; g < list->children; g++) {
7363 zend_ast_list *group = zend_ast_get_list(list->child[g]);
7364
7365 ZEND_ASSERT(group->kind == ZEND_AST_ATTRIBUTE_GROUP);
7366
7367 for (i = 0; i < group->children; i++) {
7368 ZEND_ASSERT(group->child[i]->kind == ZEND_AST_ATTRIBUTE);
7369
7370 zend_ast *el = group->child[i];
7371
7372 if (el->child[1] &&
7373 el->child[1]->kind == ZEND_AST_CALLABLE_CONVERT) {
7374 zend_error_noreturn(E_COMPILE_ERROR,
7375 "Cannot create Closure as attribute argument");
7376 }
7377
7378 zend_string *name = zend_resolve_class_name_ast(el->child[0]);
7379 zend_string *lcname = zend_string_tolower_ex(name, false);
7380 zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
7381
7382 config = zend_internal_attribute_get(lcname);
7383 zend_string_release(lcname);
7384
7385 /* Exclude internal attributes that do not match on promoted properties. */
7386 if (config && !(target & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
7387 if (promoted & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL)) {
7388 zend_string_release(name);
7389 continue;
7390 }
7391 }
7392
7393 uint32_t flags = (CG(active_op_array)->fn_flags & ZEND_ACC_STRICT_TYPES)
7394 ? ZEND_ATTRIBUTE_STRICT_TYPES : 0;
7395 attr = zend_add_attribute(
7396 attributes, name, args ? args->children : 0, flags, offset, el->lineno);
7397 zend_string_release(name);
7398
7399 /* Populate arguments */
7400 if (args) {
7401 ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);
7402
7403 bool uses_named_args = 0;
7404 for (j = 0; j < args->children; j++) {
7405 zend_ast **arg_ast_ptr = &args->child[j];
7406 zend_ast *arg_ast = *arg_ast_ptr;
7407
7408 if (arg_ast->kind == ZEND_AST_UNPACK) {
7409 zend_error_noreturn(E_COMPILE_ERROR,
7410 "Cannot use unpacking in attribute argument list");
7411 }
7412
7413 if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
7414 attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
7415 arg_ast_ptr = &arg_ast->child[1];
7416 uses_named_args = 1;
7417
7418 for (uint32_t k = 0; k < j; k++) {
7419 if (attr->args[k].name &&
7420 zend_string_equals(attr->args[k].name, attr->args[j].name)) {
7421 zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
7422 ZSTR_VAL(attr->args[j].name));
7423 }
7424 }
7425 } else if (uses_named_args) {
7426 zend_error_noreturn(E_COMPILE_ERROR,
7427 "Cannot use positional argument after named argument");
7428 }
7429
7430 zend_const_expr_to_zval(
7431 &attr->args[j].value, arg_ast_ptr, /* allow_dynamic */ true);
7432 }
7433 }
7434 }
7435 }
7436
7437 if (*attributes != NULL) {
7438 /* Validate attributes in a secondary loop (needed to detect repeated attributes). */
7439 ZEND_HASH_PACKED_FOREACH_PTR(*attributes, attr) {
7440 if (attr->offset != offset || NULL == (config = zend_internal_attribute_get(attr->lcname))) {
7441 continue;
7442 }
7443
7444 if (!(target & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
7445 zend_string *location = zend_get_attribute_target_names(target);
7446 zend_string *allowed = zend_get_attribute_target_names(config->flags);
7447
7448 zend_error_noreturn(E_ERROR, "Attribute \"%s\" cannot target %s (allowed targets: %s)",
7449 ZSTR_VAL(attr->name), ZSTR_VAL(location), ZSTR_VAL(allowed)
7450 );
7451 }
7452
7453 if (!(config->flags & ZEND_ATTRIBUTE_IS_REPEATABLE)) {
7454 if (zend_is_attribute_repeated(*attributes, attr)) {
7455 zend_error_noreturn(E_ERROR, "Attribute \"%s\" must not be repeated", ZSTR_VAL(attr->name));
7456 }
7457 }
7458
7459 if (config->validator != NULL) {
7460 config->validator(attr, target, CG(active_class_entry));
7461 }
7462 } ZEND_HASH_FOREACH_END();
7463 }
7464 }
7465 /* }}} */
7466
7467 static void zend_compile_property_hooks(
7468 zend_property_info *prop_info, zend_string *prop_name,
7469 zend_ast *prop_type_ast, zend_ast_list *hooks);
7470
7471 typedef struct {
7472 zend_string *property_name;
7473 bool uses_property;
7474 } find_property_usage_context;
7475
zend_property_hook_find_property_usage(zend_ast ** ast_ptr,void * _context)7476 static void zend_property_hook_find_property_usage(zend_ast **ast_ptr, void *_context) /* {{{ */
7477 {
7478 zend_ast *ast = *ast_ptr;
7479 find_property_usage_context *context = (find_property_usage_context *) _context;
7480
7481 if (ast == NULL) {
7482 return;
7483 } else if (ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_NULLSAFE_PROP) {
7484 zend_ast *object_ast = ast->child[0];
7485 zend_ast *property_ast = ast->child[1];
7486
7487 if (object_ast->kind == ZEND_AST_VAR
7488 && object_ast->child[0]->kind == ZEND_AST_ZVAL
7489 && property_ast->kind == ZEND_AST_ZVAL) {
7490 zval *object = zend_ast_get_zval(object_ast->child[0]);
7491 zval *property = zend_ast_get_zval(property_ast);
7492 if (Z_TYPE_P(object) == IS_STRING
7493 && Z_TYPE_P(property) == IS_STRING
7494 && zend_string_equals_literal(Z_STR_P(object), "this")
7495 && zend_string_equals(Z_STR_P(property), context->property_name)) {
7496 context->uses_property = true;
7497 /* No need to look for references in this branch. */
7498 return;
7499 }
7500 }
7501 }
7502
7503 /* Don't search across function/class boundaries. */
7504 if (!zend_ast_is_special(ast)) {
7505 zend_ast_apply(ast, zend_property_hook_find_property_usage, context);
7506 }
7507 }
7508
zend_property_hook_uses_property(zend_string * property_name,zend_string * hook_name,zend_ast * hook_ast)7509 static bool zend_property_hook_uses_property(zend_string *property_name, zend_string *hook_name, zend_ast *hook_ast)
7510 {
7511 if (zend_string_equals_literal_ci(hook_name, "set")
7512 && hook_ast->kind == ZEND_AST_PROPERTY_HOOK_SHORT_BODY) {
7513 return true;
7514 }
7515
7516 find_property_usage_context context = { property_name, false };
7517 zend_property_hook_find_property_usage(&hook_ast, &context);
7518 return context.uses_property;
7519 }
7520
zend_property_is_virtual(zend_class_entry * ce,zend_string * property_name,zend_ast * hooks_ast,uint32_t flags)7521 static bool zend_property_is_virtual(zend_class_entry *ce, zend_string *property_name, zend_ast *hooks_ast, uint32_t flags)
7522 {
7523 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
7524 return true;
7525 }
7526 if (!hooks_ast) {
7527 return false;
7528 }
7529
7530 bool is_virtual = true;
7531
7532 zend_ast_list *hooks = zend_ast_get_list(hooks_ast);
7533 for (uint32_t i = 0; i < hooks->children; i++) {
7534 zend_ast_decl *hook = (zend_ast_decl *) hooks->child[i];
7535 zend_ast *body = hook->child[2];
7536 if (body && zend_property_hook_uses_property(property_name, hook->name, body)) {
7537 is_virtual = false;
7538 }
7539 }
7540
7541 return is_virtual;
7542 }
7543
zend_compile_params(zend_ast * ast,zend_ast * return_type_ast,uint32_t fallback_return_type)7544 static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fallback_return_type) /* {{{ */
7545 {
7546 zend_ast_list *list = zend_ast_get_list(ast);
7547 uint32_t i;
7548 zend_op_array *op_array = CG(active_op_array);
7549 zend_arg_info *arg_infos;
7550
7551 if (return_type_ast || fallback_return_type) {
7552 /* Use op_array->arg_info[-1] for return type */
7553 arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children + 1, 0);
7554 arg_infos->name = NULL;
7555 if (return_type_ast) {
7556 arg_infos->type = zend_compile_typename(return_type_ast);
7557 ZEND_TYPE_FULL_MASK(arg_infos->type) |= _ZEND_ARG_INFO_FLAGS(
7558 (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0, /* is_tentative */ 0);
7559 } else {
7560 arg_infos->type = (zend_type) ZEND_TYPE_INIT_CODE(fallback_return_type, 0, 0);
7561 }
7562 arg_infos++;
7563 op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
7564
7565 if (ZEND_TYPE_CONTAINS_CODE(arg_infos[-1].type, IS_VOID)
7566 && (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
7567 zend_string *func_name = get_function_or_method_name((zend_function *) op_array);
7568 zend_error(E_DEPRECATED, "%s(): Returning by reference from a void function is deprecated", ZSTR_VAL(func_name));
7569 zend_string_release(func_name);
7570 }
7571 } else {
7572 if (list->children == 0) {
7573 return;
7574 }
7575 arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children, 0);
7576 }
7577
7578 /* Find last required parameter number for deprecation message. */
7579 uint32_t last_required_param = (uint32_t) -1;
7580 for (i = 0; i < list->children; ++i) {
7581 zend_ast *param_ast = list->child[i];
7582 zend_ast *default_ast_ptr = param_ast->child[2];
7583 bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
7584 if (!default_ast_ptr && !is_variadic) {
7585 last_required_param = i;
7586 }
7587 }
7588
7589 for (i = 0; i < list->children; ++i) {
7590 zend_ast *param_ast = list->child[i];
7591 zend_ast *type_ast = param_ast->child[0];
7592 zend_ast *var_ast = param_ast->child[1];
7593 zend_ast **default_ast_ptr = ¶m_ast->child[2];
7594 zend_ast *attributes_ast = param_ast->child[3];
7595 zend_ast *doc_comment_ast = param_ast->child[4];
7596 zend_ast *hooks_ast = param_ast->child[5];
7597 zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast));
7598 bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
7599 bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
7600 uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY);
7601 bool is_promoted = property_flags || hooks_ast;
7602
7603 znode var_node, default_node;
7604 uint8_t opcode;
7605 zend_op *opline;
7606 zend_arg_info *arg_info;
7607
7608 if (zend_is_auto_global(name)) {
7609 zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s",
7610 ZSTR_VAL(name));
7611 }
7612
7613 var_node.op_type = IS_CV;
7614 var_node.u.op.var = lookup_cv(name);
7615
7616 if (EX_VAR_TO_NUM(var_node.u.op.var) != i) {
7617 zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s",
7618 ZSTR_VAL(name));
7619 } else if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS))) {
7620 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter");
7621 }
7622
7623 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
7624 zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic");
7625 }
7626
7627 if (is_variadic) {
7628 opcode = ZEND_RECV_VARIADIC;
7629 default_node.op_type = IS_UNUSED;
7630 op_array->fn_flags |= ZEND_ACC_VARIADIC;
7631
7632 if (*default_ast_ptr) {
7633 zend_error_noreturn(E_COMPILE_ERROR,
7634 "Variadic parameter cannot have a default value");
7635 }
7636 } else if (*default_ast_ptr) {
7637 /* we cannot substitute constants here or it will break ReflectionParameter::getDefaultValueConstantName() and ReflectionParameter::isDefaultValueConstant() */
7638 uint32_t cops = CG(compiler_options);
7639 CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION;
7640 opcode = ZEND_RECV_INIT;
7641 default_node.op_type = IS_CONST;
7642 zend_const_expr_to_zval(
7643 &default_node.u.constant, default_ast_ptr, /* allow_dynamic */ true);
7644 CG(compiler_options) = cops;
7645 } else {
7646 opcode = ZEND_RECV;
7647 default_node.op_type = IS_UNUSED;
7648 op_array->required_num_args = i + 1;
7649 }
7650
7651 arg_info = &arg_infos[i];
7652 arg_info->name = zend_string_copy(name);
7653 arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0);
7654
7655 if (attributes_ast) {
7656 zend_compile_attributes(
7657 &op_array->attributes, attributes_ast, i + 1, ZEND_ATTRIBUTE_TARGET_PARAMETER,
7658 is_promoted ? ZEND_ATTRIBUTE_TARGET_PROPERTY : 0
7659 );
7660 }
7661
7662 bool forced_allow_nullable = false;
7663 if (type_ast) {
7664 uint32_t default_type = *default_ast_ptr ? Z_TYPE(default_node.u.constant) : IS_UNDEF;
7665 bool force_nullable = default_type == IS_NULL && !is_promoted;
7666
7667 op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
7668 arg_info->type = zend_compile_typename_ex(type_ast, force_nullable, &forced_allow_nullable);
7669 if (forced_allow_nullable) {
7670 zend_string *func_name = get_function_or_method_name((zend_function *) op_array);
7671 zend_error(E_DEPRECATED,
7672 "%s(): Implicitly marking parameter $%s as nullable is deprecated, the explicit nullable type "
7673 "must be used instead", ZSTR_VAL(func_name), ZSTR_VAL(name));
7674 zend_string_release(func_name);
7675 }
7676
7677 if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_VOID) {
7678 zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type");
7679 }
7680
7681 if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_NEVER) {
7682 zend_error_noreturn(E_COMPILE_ERROR, "never cannot be used as a parameter type");
7683 }
7684
7685 if (default_type != IS_UNDEF && default_type != IS_CONSTANT_AST && !force_nullable
7686 && !zend_is_valid_default_value(arg_info->type, &default_node.u.constant)) {
7687 zend_string *type_str = zend_type_to_string(arg_info->type);
7688 zend_error_noreturn(E_COMPILE_ERROR,
7689 "Cannot use %s as default value for parameter $%s of type %s",
7690 zend_get_type_by_const(default_type),
7691 ZSTR_VAL(name), ZSTR_VAL(type_str));
7692 }
7693 }
7694 if (last_required_param != (uint32_t) -1
7695 && i < last_required_param
7696 && default_node.op_type == IS_CONST) {
7697 /* Ignore parameters of the form "Type $param = null".
7698 * This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
7699 if (!forced_allow_nullable) {
7700 zend_string *func_name = get_function_or_method_name((zend_function *) op_array);
7701 zend_ast *required_param_ast = list->child[last_required_param];
7702 zend_error(E_DEPRECATED,
7703 "%s(): Optional parameter $%s declared before required parameter $%s "
7704 "is implicitly treated as a required parameter",
7705 ZSTR_VAL(func_name), ZSTR_VAL(name), ZSTR_VAL(zend_ast_get_str(required_param_ast->child[1])));
7706 zend_string_release(func_name);
7707 }
7708
7709 /* Regardless of whether we issue a deprecation, convert this parameter into
7710 * a required parameter without a default value. This ensures that it cannot be
7711 * used as an optional parameter even with named parameters. */
7712 opcode = ZEND_RECV;
7713 default_node.op_type = IS_UNUSED;
7714 zval_ptr_dtor(&default_node.u.constant);
7715 }
7716
7717 opline = zend_emit_op(NULL, opcode, NULL, &default_node);
7718 SET_NODE(opline->result, &var_node);
7719 opline->op1.num = i + 1;
7720
7721 if (type_ast) {
7722 /* Allocate cache slot to speed-up run-time class resolution */
7723 opline->extended_value =
7724 zend_alloc_cache_slots(zend_type_get_num_classes(arg_info->type));
7725 }
7726
7727 uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0)
7728 | (is_promoted ? _ZEND_IS_PROMOTED_BIT : 0);
7729 ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags;
7730 if (opcode == ZEND_RECV) {
7731 opline->op2.num = type_ast ?
7732 ZEND_TYPE_FULL_MASK(arg_info->type) : MAY_BE_ANY;
7733 }
7734
7735 if (is_promoted) {
7736 zend_op_array *op_array = CG(active_op_array);
7737 zend_class_entry *scope = op_array->scope;
7738
7739 bool is_ctor =
7740 scope && zend_is_constructor(op_array->function_name);
7741 if (!is_ctor) {
7742 zend_error_noreturn(E_COMPILE_ERROR,
7743 "Cannot declare promoted property outside a constructor");
7744 }
7745 if ((op_array->fn_flags & ZEND_ACC_ABSTRACT)
7746 || (scope->ce_flags & ZEND_ACC_INTERFACE)) {
7747 zend_error_noreturn(E_COMPILE_ERROR,
7748 "Cannot declare promoted property in an abstract constructor");
7749 }
7750 if (is_variadic) {
7751 zend_error_noreturn(E_COMPILE_ERROR,
7752 "Cannot declare variadic promoted property");
7753 }
7754 if (zend_hash_exists(&scope->properties_info, name)) {
7755 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::$%s",
7756 ZSTR_VAL(scope->name), ZSTR_VAL(name));
7757 }
7758 if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_CALLABLE) {
7759 zend_string *str = zend_type_to_string(arg_info->type);
7760 zend_error_noreturn(E_COMPILE_ERROR,
7761 "Property %s::$%s cannot have type %s",
7762 ZSTR_VAL(scope->name), ZSTR_VAL(name), ZSTR_VAL(str));
7763 }
7764
7765 if (!(property_flags & ZEND_ACC_READONLY) && (scope->ce_flags & ZEND_ACC_READONLY_CLASS)) {
7766 property_flags |= ZEND_ACC_READONLY;
7767 }
7768
7769 /* Recompile the type, as it has different memory management requirements. */
7770 zend_type type = ZEND_TYPE_INIT_NONE(0);
7771 if (type_ast) {
7772 type = zend_compile_typename(type_ast);
7773 }
7774
7775 /* Don't give the property an explicit default value. For typed properties this means
7776 * uninitialized, for untyped properties it means an implicit null default value.
7777 * Properties with hooks get an implicit default value of undefined until inheritance,
7778 * where it is changed to null only once we know it is not virtual. If we were to set it
7779 * here, we couldn't verify that a true virtual property must not have an explicit
7780 * default value. */
7781 zval default_value;
7782 if (ZEND_TYPE_IS_SET(type) || hooks_ast) {
7783 ZVAL_UNDEF(&default_value);
7784 } else {
7785 if (property_flags & ZEND_ACC_READONLY) {
7786 zend_error_noreturn(E_COMPILE_ERROR, "Readonly property %s::$%s must have type",
7787 ZSTR_VAL(scope->name), ZSTR_VAL(name));
7788 }
7789
7790 ZVAL_NULL(&default_value);
7791 }
7792
7793 zend_string *doc_comment =
7794 doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
7795 zend_property_info *prop = zend_declare_typed_property(
7796 scope, name, &default_value,
7797 property_flags | (zend_property_is_virtual(scope, name, hooks_ast, property_flags) ? ZEND_ACC_VIRTUAL : 0) | ZEND_ACC_PROMOTED,
7798 doc_comment, type);
7799 if (hooks_ast) {
7800 zend_ast_list *hooks = zend_ast_get_list(hooks_ast);
7801 zend_compile_property_hooks(prop, name, type_ast, hooks);
7802 }
7803 if (attributes_ast) {
7804 zend_compile_attributes(
7805 &prop->attributes, attributes_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, ZEND_ATTRIBUTE_TARGET_PARAMETER);
7806 }
7807 }
7808 }
7809
7810 /* These are assigned at the end to avoid uninitialized memory in case of an error */
7811 op_array->num_args = list->children;
7812 op_array->arg_info = arg_infos;
7813
7814 /* Don't count the variadic argument */
7815 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
7816 op_array->num_args--;
7817 }
7818 zend_set_function_arg_flags((zend_function*)op_array);
7819
7820 for (i = 0; i < list->children; i++) {
7821 zend_ast *param_ast = list->child[i];
7822 zend_ast *hooks_ast = param_ast->child[5];
7823 bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
7824 uint32_t flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY);
7825 bool is_promoted = flags || hooks_ast;
7826 if (!is_promoted) {
7827 continue;
7828 }
7829
7830 /* Emit $this->prop = $prop for promoted properties. */
7831 zend_string *name = zend_ast_get_str(param_ast->child[1]);
7832 znode name_node, value_node;
7833 name_node.op_type = IS_CONST;
7834 ZVAL_STR_COPY(&name_node.u.constant, name);
7835 value_node.op_type = IS_CV;
7836 value_node.u.op.var = lookup_cv(name);
7837
7838 zend_op *opline = zend_emit_op(NULL,
7839 is_ref ? ZEND_ASSIGN_OBJ_REF : ZEND_ASSIGN_OBJ, NULL, &name_node);
7840 opline->extended_value = zend_alloc_cache_slots(3);
7841 zend_emit_op_data(&value_node);
7842 }
7843 }
7844 /* }}} */
7845
zend_compile_closure_binding(znode * closure,zend_op_array * op_array,zend_ast * uses_ast)7846 static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array, zend_ast *uses_ast) /* {{{ */
7847 {
7848 zend_ast_list *list = zend_ast_get_list(uses_ast);
7849 uint32_t i;
7850
7851 if (!list->children) {
7852 return;
7853 }
7854
7855 if (!op_array->static_variables) {
7856 op_array->static_variables = zend_new_array(8);
7857 }
7858
7859 for (i = 0; i < list->children; ++i) {
7860 zend_ast *var_name_ast = list->child[i];
7861 zend_string *var_name = zval_make_interned_string(zend_ast_get_zval(var_name_ast));
7862 uint32_t mode = var_name_ast->attr;
7863 zend_op *opline;
7864 zval *value;
7865
7866 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
7867 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
7868 }
7869
7870 if (zend_is_auto_global(var_name)) {
7871 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable");
7872 }
7873
7874 value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval));
7875 if (!value) {
7876 zend_error_noreturn_unchecked(E_COMPILE_ERROR,
7877 "Cannot use variable $%S twice", var_name);
7878 }
7879
7880 CG(zend_lineno) = zend_ast_get_lineno(var_name_ast);
7881
7882 opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
7883 opline->op2_type = IS_CV;
7884 opline->op2.var = lookup_cv(var_name);
7885 opline->extended_value =
7886 (uint32_t)((char*)value - (char*)op_array->static_variables->arData) | mode;
7887 }
7888 }
7889 /* }}} */
7890
7891 typedef struct {
7892 HashTable uses;
7893 bool varvars_used;
7894 } closure_info;
7895
find_implicit_binds_recursively(closure_info * info,zend_ast * ast)7896 static void find_implicit_binds_recursively(closure_info *info, zend_ast *ast) {
7897 if (!ast) {
7898 return;
7899 }
7900
7901 if (ast->kind == ZEND_AST_VAR) {
7902 zend_ast *name_ast = ast->child[0];
7903 if (name_ast->kind == ZEND_AST_ZVAL && Z_TYPE_P(zend_ast_get_zval(name_ast)) == IS_STRING) {
7904 zend_string *name = zend_ast_get_str(name_ast);
7905 if (zend_is_auto_global(name)) {
7906 /* These is no need to explicitly import auto-globals. */
7907 return;
7908 }
7909
7910 if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_THIS))) {
7911 /* $this does not need to be explicitly imported. */
7912 return;
7913 }
7914
7915 zend_hash_add_empty_element(&info->uses, name);
7916 } else {
7917 info->varvars_used = 1;
7918 find_implicit_binds_recursively(info, name_ast);
7919 }
7920 } else if (zend_ast_is_list(ast)) {
7921 zend_ast_list *list = zend_ast_get_list(ast);
7922 uint32_t i;
7923 for (i = 0; i < list->children; i++) {
7924 find_implicit_binds_recursively(info, list->child[i]);
7925 }
7926 } else if (ast->kind == ZEND_AST_CLOSURE) {
7927 /* For normal closures add the use() list. */
7928 zend_ast_decl *closure_ast = (zend_ast_decl *) ast;
7929 zend_ast *uses_ast = closure_ast->child[1];
7930 if (uses_ast) {
7931 zend_ast_list *uses_list = zend_ast_get_list(uses_ast);
7932 uint32_t i;
7933 for (i = 0; i < uses_list->children; i++) {
7934 zend_hash_add_empty_element(&info->uses, zend_ast_get_str(uses_list->child[i]));
7935 }
7936 }
7937 } else if (ast->kind == ZEND_AST_ARROW_FUNC) {
7938 /* For arrow functions recursively check the expression. */
7939 zend_ast_decl *closure_ast = (zend_ast_decl *) ast;
7940 find_implicit_binds_recursively(info, closure_ast->child[2]);
7941 } else if (!zend_ast_is_special(ast)) {
7942 uint32_t i, children = zend_ast_get_num_children(ast);
7943 for (i = 0; i < children; i++) {
7944 find_implicit_binds_recursively(info, ast->child[i]);
7945 }
7946 }
7947 }
7948
find_implicit_binds(closure_info * info,zend_ast * params_ast,zend_ast * stmt_ast)7949 static void find_implicit_binds(closure_info *info, zend_ast *params_ast, zend_ast *stmt_ast)
7950 {
7951 zend_ast_list *param_list = zend_ast_get_list(params_ast);
7952 uint32_t i;
7953
7954 zend_hash_init(&info->uses, param_list->children, NULL, NULL, 0);
7955
7956 find_implicit_binds_recursively(info, stmt_ast);
7957
7958 /* Remove variables that are parameters */
7959 for (i = 0; i < param_list->children; i++) {
7960 zend_ast *param_ast = param_list->child[i];
7961 zend_hash_del(&info->uses, zend_ast_get_str(param_ast->child[1]));
7962 }
7963 }
7964
compile_implicit_lexical_binds(closure_info * info,znode * closure,zend_op_array * op_array)7965 static void compile_implicit_lexical_binds(
7966 closure_info *info, znode *closure, zend_op_array *op_array)
7967 {
7968 zend_string *var_name;
7969 zend_op *opline;
7970
7971 /* TODO We might want to use a special binding mode if varvars_used is set. */
7972 if (zend_hash_num_elements(&info->uses) == 0) {
7973 return;
7974 }
7975
7976 if (!op_array->static_variables) {
7977 op_array->static_variables = zend_new_array(8);
7978 }
7979
7980 ZEND_HASH_MAP_FOREACH_STR_KEY(&info->uses, var_name)
7981 zval *value = zend_hash_add(
7982 op_array->static_variables, var_name, &EG(uninitialized_zval));
7983 uint32_t offset = (uint32_t)((char*)value - (char*)op_array->static_variables->arData);
7984
7985 opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
7986 opline->op2_type = IS_CV;
7987 opline->op2.var = lookup_cv(var_name);
7988 opline->extended_value = offset | ZEND_BIND_IMPLICIT;
7989 ZEND_HASH_FOREACH_END();
7990 }
7991
zend_compile_closure_uses(zend_ast * ast)7992 static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
7993 {
7994 zend_op_array *op_array = CG(active_op_array);
7995 zend_ast_list *list = zend_ast_get_list(ast);
7996 uint32_t i;
7997
7998 for (i = 0; i < list->children; ++i) {
7999 uint32_t mode = ZEND_BIND_EXPLICIT;
8000 zend_ast *var_ast = list->child[i];
8001 zend_string *var_name = zend_ast_get_str(var_ast);
8002 zval zv;
8003 ZVAL_NULL(&zv);
8004
8005 {
8006 int i;
8007 for (i = 0; i < op_array->last_var; i++) {
8008 if (zend_string_equals(op_array->vars[i], var_name)) {
8009 zend_error_noreturn_unchecked(E_COMPILE_ERROR,
8010 "Cannot use lexical variable $%S as a parameter name", var_name);
8011 }
8012 }
8013 }
8014
8015 CG(zend_lineno) = zend_ast_get_lineno(var_ast);
8016
8017 if (var_ast->attr) {
8018 mode |= ZEND_BIND_REF;
8019 }
8020
8021 zend_compile_static_var_common(var_name, &zv, mode);
8022 }
8023 }
8024 /* }}} */
8025
zend_compile_implicit_closure_uses(closure_info * info)8026 static void zend_compile_implicit_closure_uses(closure_info *info)
8027 {
8028 zend_string *var_name;
8029 ZEND_HASH_MAP_FOREACH_STR_KEY(&info->uses, var_name)
8030 zval zv;
8031 ZVAL_NULL(&zv);
8032 zend_compile_static_var_common(var_name, &zv, ZEND_BIND_IMPLICIT);
8033 ZEND_HASH_FOREACH_END();
8034 }
8035
add_stringable_interface(zend_class_entry * ce)8036 static void add_stringable_interface(zend_class_entry *ce) {
8037 for (uint32_t i = 0; i < ce->num_interfaces; i++) {
8038 if (zend_string_equals_literal(ce->interface_names[i].lc_name, "stringable")) {
8039 /* Interface already explicitly implemented */
8040 return;
8041 }
8042 }
8043
8044 ce->num_interfaces++;
8045 ce->interface_names =
8046 erealloc(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
8047 // TODO: Add known interned strings instead?
8048 ce->interface_names[ce->num_interfaces - 1].name =
8049 ZSTR_INIT_LITERAL("Stringable", 0);
8050 ce->interface_names[ce->num_interfaces - 1].lc_name =
8051 ZSTR_INIT_LITERAL("stringable", 0);
8052 }
8053
zend_begin_method_decl(zend_op_array * op_array,zend_string * name,bool has_body)8054 static zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name, bool has_body) /* {{{ */
8055 {
8056 zend_class_entry *ce = CG(active_class_entry);
8057 bool in_interface = (ce->ce_flags & ZEND_ACC_INTERFACE) != 0;
8058 uint32_t fn_flags = op_array->fn_flags;
8059
8060 zend_string *lcname;
8061
8062 if (fn_flags & ZEND_ACC_READONLY) {
8063 zend_error(E_COMPILE_ERROR, "Cannot use 'readonly' as method modifier");
8064 }
8065
8066 if ((fn_flags & ZEND_ACC_PRIVATE) && (fn_flags & ZEND_ACC_FINAL) && !zend_is_constructor(name)) {
8067 zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
8068 }
8069
8070 if (in_interface) {
8071 if (!(fn_flags & ZEND_ACC_PUBLIC)) {
8072 zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface method "
8073 "%s::%s() must be public", ZSTR_VAL(ce->name), ZSTR_VAL(name));
8074 }
8075 if (fn_flags & ZEND_ACC_FINAL) {
8076 zend_error_noreturn(E_COMPILE_ERROR, "Interface method "
8077 "%s::%s() must not be final", ZSTR_VAL(ce->name), ZSTR_VAL(name));
8078 }
8079 if (fn_flags & ZEND_ACC_ABSTRACT) {
8080 zend_error_noreturn(E_COMPILE_ERROR, "Interface method "
8081 "%s::%s() must not be abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
8082 }
8083 op_array->fn_flags |= ZEND_ACC_ABSTRACT;
8084 }
8085
8086 if (op_array->fn_flags & ZEND_ACC_ABSTRACT) {
8087 if ((op_array->fn_flags & ZEND_ACC_PRIVATE) && !(ce->ce_flags & ZEND_ACC_TRAIT)) {
8088 zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private",
8089 in_interface ? "Interface" : "Abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
8090 }
8091
8092 if (has_body) {
8093 zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body",
8094 in_interface ? "Interface" : "Abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
8095 }
8096
8097 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
8098 } else if (!has_body) {
8099 zend_error_noreturn(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body",
8100 ZSTR_VAL(ce->name), ZSTR_VAL(name));
8101 }
8102
8103 op_array->scope = ce;
8104 op_array->function_name = zend_string_copy(name);
8105
8106 lcname = zend_string_tolower(name);
8107 lcname = zend_new_interned_string(lcname);
8108
8109 if (zend_hash_add_ptr(&ce->function_table, lcname, op_array) == NULL) {
8110 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::%s()",
8111 ZSTR_VAL(ce->name), ZSTR_VAL(name));
8112 }
8113
8114 zend_add_magic_method(ce, (zend_function *) op_array, lcname);
8115 if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)
8116 && !(ce->ce_flags & ZEND_ACC_TRAIT)) {
8117 add_stringable_interface(ce);
8118 }
8119
8120 return lcname;
8121 }
8122 /* }}} */
8123
zend_add_dynamic_func_def(zend_op_array * def)8124 static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
8125 zend_op_array *op_array = CG(active_op_array);
8126 uint32_t def_offset = op_array->num_dynamic_func_defs++;
8127 op_array->dynamic_func_defs = erealloc(
8128 op_array->dynamic_func_defs, op_array->num_dynamic_func_defs * sizeof(zend_op_array *));
8129 op_array->dynamic_func_defs[def_offset] = def;
8130 return def_offset;
8131 }
8132
zend_begin_func_decl(znode * result,zend_op_array * op_array,zend_ast_decl * decl,bool toplevel)8133 static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
8134 {
8135 zend_string *unqualified_name, *name, *lcname;
8136 zend_op *opline;
8137
8138 if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
8139 zend_string *filename = op_array->filename;
8140 uint32_t start_lineno = decl->start_lineno;
8141
8142 zend_string *class = zend_empty_string;
8143 zend_string *separator = zend_empty_string;
8144 zend_string *function = filename;
8145 char *parens = "";
8146
8147 if (CG(active_op_array) && CG(active_op_array)->function_name) {
8148 if (CG(active_op_array)->fn_flags & ZEND_ACC_CLOSURE) {
8149 /* If the parent function is a closure, don't redundantly
8150 * add the classname and parentheses.
8151 */
8152 function = CG(active_op_array)->function_name;
8153 } else {
8154 function = CG(active_op_array)->function_name;
8155 parens = "()";
8156
8157 if (CG(active_class_entry) && CG(active_class_entry)->name) {
8158 class = CG(active_class_entry)->name;
8159 separator = ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM);
8160 }
8161 }
8162 }
8163
8164 unqualified_name = zend_strpprintf_unchecked(
8165 0,
8166 "{closure:%S%S%S%s:%" PRIu32 "}",
8167 class,
8168 separator,
8169 function,
8170 parens,
8171 start_lineno
8172 );
8173
8174 op_array->function_name = name = unqualified_name;
8175 } else {
8176 unqualified_name = decl->name;
8177 op_array->function_name = name = zend_prefix_with_ns(unqualified_name);
8178 }
8179
8180 lcname = zend_string_tolower(name);
8181
8182 if (FC(imports_function)) {
8183 zend_string *import_name =
8184 zend_hash_find_ptr_lc(FC(imports_function), unqualified_name);
8185 if (import_name && !zend_string_equals_ci(lcname, import_name)) {
8186 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare function %s() (previously declared as local import)",
8187 ZSTR_VAL(name));
8188 }
8189 }
8190
8191 if (zend_string_equals_literal(lcname, "__autoload")) {
8192 zend_error_noreturn(E_COMPILE_ERROR,
8193 "__autoload() is no longer supported, use spl_autoload_register() instead");
8194 }
8195
8196 if (zend_string_equals_literal_ci(unqualified_name, "assert")) {
8197 zend_error(E_COMPILE_ERROR,
8198 "Defining a custom assert() function is not allowed, "
8199 "as the function has special semantics");
8200 }
8201
8202 zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION);
8203 if (!toplevel) {
8204 uint32_t func_ref = zend_add_dynamic_func_def(op_array);
8205 if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
8206 opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
8207 opline->op2.num = func_ref;
8208 } else {
8209 opline = get_next_op();
8210 opline->opcode = ZEND_DECLARE_FUNCTION;
8211 opline->op1_type = IS_CONST;
8212 LITERAL_STR(opline->op1, zend_string_copy(lcname));
8213 opline->op2.num = func_ref;
8214 }
8215 }
8216 return lcname;
8217 }
8218 /* }}} */
8219
zend_compile_func_decl_ex(znode * result,zend_ast * ast,bool toplevel,const zend_property_info * property_info,zend_property_hook_kind hook_kind)8220 static zend_op_array *zend_compile_func_decl_ex(
8221 znode *result, zend_ast *ast, bool toplevel,
8222 const zend_property_info *property_info,
8223 zend_property_hook_kind hook_kind
8224 ) {
8225 zend_ast_decl *decl = (zend_ast_decl *) ast;
8226 zend_ast *params_ast = decl->child[0];
8227 zend_ast *uses_ast = decl->child[1];
8228 zend_ast *stmt_ast = decl->child[2];
8229 zend_ast *return_type_ast = decl->child[3];
8230 bool is_method = decl->kind == ZEND_AST_METHOD;
8231 zend_string *lcname = NULL;
8232 bool is_hook = decl->kind == ZEND_AST_PROPERTY_HOOK;
8233
8234 zend_class_entry *orig_class_entry = CG(active_class_entry);
8235 zend_op_array *orig_op_array = CG(active_op_array);
8236 zend_op_array *op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
8237 zend_oparray_context orig_oparray_context;
8238 closure_info info;
8239 memset(&info, 0, sizeof(closure_info));
8240
8241 init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE);
8242
8243 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
8244 op_array->fn_flags |= ZEND_ACC_PRELOADED;
8245 }
8246
8247 op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_STRICT_TYPES);
8248 op_array->fn_flags |= decl->flags;
8249 op_array->line_start = decl->start_lineno;
8250 op_array->line_end = decl->end_lineno;
8251 if (decl->doc_comment) {
8252 op_array->doc_comment = zend_string_copy(decl->doc_comment);
8253 }
8254
8255 if (decl->kind == ZEND_AST_CLOSURE || decl->kind == ZEND_AST_ARROW_FUNC) {
8256 op_array->fn_flags |= ZEND_ACC_CLOSURE;
8257 }
8258
8259 if (is_hook) {
8260 zend_class_entry *ce = CG(active_class_entry);
8261 op_array->scope = ce;
8262 op_array->function_name = zend_string_copy(decl->name);
8263 } else if (is_method) {
8264 bool has_body = stmt_ast != NULL;
8265 lcname = zend_begin_method_decl(op_array, decl->name, has_body);
8266 } else {
8267 lcname = zend_begin_func_decl(result, op_array, decl, toplevel);
8268 if (decl->kind == ZEND_AST_ARROW_FUNC) {
8269 find_implicit_binds(&info, params_ast, stmt_ast);
8270 compile_implicit_lexical_binds(&info, result, op_array);
8271 } else if (uses_ast) {
8272 zend_compile_closure_binding(result, op_array, uses_ast);
8273 }
8274 }
8275
8276 CG(active_op_array) = op_array;
8277
8278 if (decl->child[4]) {
8279 int target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
8280
8281 if (is_method || is_hook) {
8282 target = ZEND_ATTRIBUTE_TARGET_METHOD;
8283 }
8284
8285 zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0);
8286
8287 zend_attribute *override_attribute = zend_get_attribute_str(
8288 op_array->attributes,
8289 "override",
8290 sizeof("override")-1
8291 );
8292
8293 if (override_attribute) {
8294 op_array->fn_flags |= ZEND_ACC_OVERRIDE;
8295 }
8296
8297 zend_attribute *deprecated_attribute = zend_get_attribute_str(
8298 op_array->attributes,
8299 "deprecated",
8300 sizeof("deprecated")-1
8301 );
8302
8303 if (deprecated_attribute) {
8304 op_array->fn_flags |= ZEND_ACC_DEPRECATED;
8305 }
8306 }
8307
8308 /* Do not leak the class scope into free standing functions, even if they are dynamically
8309 * defined inside a class method. This is necessary for correct handling of magic constants.
8310 * For example __CLASS__ should always be "" inside a free standing function. */
8311 if (decl->kind == ZEND_AST_FUNC_DECL) {
8312 CG(active_class_entry) = NULL;
8313 }
8314
8315 if (toplevel) {
8316 op_array->fn_flags |= ZEND_ACC_TOP_LEVEL;
8317 }
8318
8319 zend_oparray_context_begin(&orig_oparray_context, op_array);
8320 CG(context).active_property_info = property_info;
8321 CG(context).active_property_hook_kind = hook_kind;
8322
8323 {
8324 /* Push a separator to the loop variable stack */
8325 zend_loop_var dummy_var;
8326 dummy_var.opcode = ZEND_RETURN;
8327
8328 zend_stack_push(&CG(loop_var_stack), (void *) &dummy_var);
8329 }
8330
8331 zend_compile_params(params_ast, return_type_ast,
8332 is_method && zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0);
8333 if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
8334 zend_mark_function_as_generator();
8335 zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
8336 }
8337 if (decl->kind == ZEND_AST_ARROW_FUNC) {
8338 zend_compile_implicit_closure_uses(&info);
8339 zend_hash_destroy(&info.uses);
8340 } else if (uses_ast) {
8341 zend_compile_closure_uses(uses_ast);
8342 }
8343
8344 if (ast->kind == ZEND_AST_ARROW_FUNC && decl->child[2]->kind != ZEND_AST_RETURN) {
8345 bool needs_return = true;
8346 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
8347 zend_arg_info *return_info = CG(active_op_array)->arg_info - 1;
8348 needs_return = !ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_NEVER);
8349 }
8350 if (needs_return) {
8351 stmt_ast = zend_ast_create(ZEND_AST_RETURN, stmt_ast);
8352 decl->child[2] = stmt_ast;
8353 }
8354 }
8355
8356 zend_compile_stmt(stmt_ast);
8357
8358 if (is_method) {
8359 CG(zend_lineno) = decl->start_lineno;
8360 zend_check_magic_method_implementation(
8361 CG(active_class_entry), (zend_function *) op_array, lcname, E_COMPILE_ERROR);
8362 } else if (toplevel) {
8363 /* Only register the function after a successful compile */
8364 if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) {
8365 CG(zend_lineno) = decl->start_lineno;
8366 do_bind_function_error(lcname, op_array, true);
8367 }
8368 }
8369
8370 /* put the implicit return on the really last line */
8371 CG(zend_lineno) = decl->end_lineno;
8372
8373 zend_do_extended_stmt();
8374 zend_emit_final_return(0);
8375
8376 pass_two(CG(active_op_array));
8377 zend_oparray_context_end(&orig_oparray_context);
8378
8379 /* Pop the loop variable stack separator */
8380 zend_stack_del_top(&CG(loop_var_stack));
8381
8382 if (toplevel) {
8383 zend_observer_function_declared_notify(op_array, lcname);
8384 }
8385
8386 if (lcname != NULL) {
8387 zend_string_release_ex(lcname, 0);
8388 }
8389
8390 CG(active_op_array) = orig_op_array;
8391 CG(active_class_entry) = orig_class_entry;
8392
8393 return op_array;
8394 }
8395
zend_compile_func_decl(znode * result,zend_ast * ast,bool toplevel)8396 static zend_op_array *zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
8397 {
8398 return zend_compile_func_decl_ex(result, ast, toplevel, /* property_info */ NULL, (zend_property_hook_kind)-1);
8399 }
8400
zend_get_property_hook_kind_from_name(zend_string * name)8401 zend_property_hook_kind zend_get_property_hook_kind_from_name(zend_string *name) {
8402 if (zend_string_equals_literal_ci(name, "get")) {
8403 return ZEND_PROPERTY_HOOK_GET;
8404 } else if (zend_string_equals_literal_ci(name, "set")) {
8405 return ZEND_PROPERTY_HOOK_SET;
8406 } else {
8407 return (zend_property_hook_kind)-1;
8408 }
8409 }
8410
zend_compile_property_hooks(zend_property_info * prop_info,zend_string * prop_name,zend_ast * prop_type_ast,zend_ast_list * hooks)8411 static void zend_compile_property_hooks(
8412 zend_property_info *prop_info, zend_string *prop_name,
8413 zend_ast *prop_type_ast, zend_ast_list *hooks)
8414 {
8415 zend_class_entry *ce = CG(active_class_entry);
8416
8417 if (prop_info->flags & ZEND_ACC_READONLY) {
8418 zend_error_noreturn(E_COMPILE_ERROR, "Hooked properties cannot be readonly");
8419 }
8420
8421 if (hooks->children == 0) {
8422 zend_error_noreturn(E_COMPILE_ERROR, "Property hook list must not be empty");
8423 }
8424
8425 for (uint32_t i = 0; i < hooks->children; i++) {
8426 zend_ast_decl *hook = (zend_ast_decl *) hooks->child[i];
8427 zend_string *name = hook->name;
8428 zend_ast *stmt_ast = hook->child[2];
8429 zend_ast **return_type_ast_ptr = NULL;
8430 zend_ast **value_type_ast_ptr = NULL;
8431 CG(zend_lineno) = hook->start_lineno;
8432
8433 /* Non-private hooks are always public. This avoids having to copy the hook when inheriting
8434 * hooks from protected properties to public ones. */
8435 uint32_t hook_visibility = (prop_info->flags & ZEND_ACC_PPP_MASK) != ZEND_ACC_PRIVATE ? ZEND_ACC_PUBLIC : ZEND_ACC_PRIVATE;
8436 hook->flags |= hook_visibility;
8437
8438 if (prop_info->flags & ZEND_ACC_STATIC) {
8439 zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare hooks for static property");
8440 }
8441 if ((hook->flags & ZEND_ACC_FINAL) && (hook->flags & ZEND_ACC_PRIVATE)) {
8442 zend_error_noreturn(E_COMPILE_ERROR, "Property hook cannot be both final and private");
8443 }
8444 if ((ce->ce_flags & ZEND_ACC_INTERFACE)
8445 || ((prop_info->flags & ZEND_ACC_ABSTRACT) && !stmt_ast)) {
8446 hook->flags |= ZEND_ACC_ABSTRACT;
8447
8448 if (stmt_ast) {
8449 zend_error_noreturn(E_COMPILE_ERROR, "Abstract property hook cannot have body");
8450 }
8451 if (hook->flags & ZEND_ACC_PRIVATE) {
8452 zend_error_noreturn(E_COMPILE_ERROR,
8453 "Property hook cannot be both abstract and private");
8454 }
8455 if (hook->flags & ZEND_ACC_FINAL) {
8456 zend_error_noreturn(E_COMPILE_ERROR, "Property hook cannot be both abstract and final");
8457 }
8458 } else if (!stmt_ast) {
8459 zend_error_noreturn(E_COMPILE_ERROR, "Non-abstract property hook must have a body");
8460 }
8461
8462 zend_property_hook_kind hook_kind = zend_get_property_hook_kind_from_name(name);
8463 if (hook_kind == (zend_property_hook_kind)-1) {
8464 zend_error_noreturn(E_COMPILE_ERROR,
8465 "Unknown hook \"%s\" for property %s::$%s, expected \"get\" or \"set\"",
8466 ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
8467 }
8468
8469 if (stmt_ast && stmt_ast->kind == ZEND_AST_PROPERTY_HOOK_SHORT_BODY) {
8470 stmt_ast = stmt_ast->child[0];
8471 if (hook_kind == ZEND_PROPERTY_HOOK_GET) {
8472 stmt_ast = zend_ast_create(ZEND_AST_RETURN, stmt_ast);
8473 } else {
8474 ZEND_ASSERT(hook_kind == ZEND_PROPERTY_HOOK_SET);
8475 stmt_ast = zend_ast_create(ZEND_AST_ASSIGN,
8476 zend_ast_create(ZEND_AST_PROP,
8477 zend_ast_create(ZEND_AST_VAR, zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_THIS))),
8478 zend_ast_create_zval_from_str(zend_copy_unmangled_prop_name(prop_info->name))),
8479 stmt_ast);
8480 }
8481 stmt_ast = zend_ast_create_list(1, ZEND_AST_STMT_LIST, stmt_ast);
8482 hook->child[2] = stmt_ast;
8483 }
8484
8485 if (hook_kind == ZEND_PROPERTY_HOOK_GET) {
8486 if (hook->child[0]) {
8487 zend_error_noreturn(E_COMPILE_ERROR, "get hook of property %s::$%s must not have a parameter list",
8488 ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
8489 }
8490
8491 hook->child[0] = zend_ast_create_list(0, ZEND_AST_PARAM_LIST);
8492
8493 return_type_ast_ptr = &hook->child[3];
8494 *return_type_ast_ptr = prop_type_ast;
8495 } else if (hook_kind == ZEND_PROPERTY_HOOK_SET) {
8496 if (hook->child[0]) {
8497 zend_ast_list *param_list = zend_ast_get_list(hook->child[0]);
8498 if (param_list->children != 1) {
8499 zend_error_noreturn(E_COMPILE_ERROR, "%s hook of property %s::$%s must accept exactly one parameters",
8500 ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
8501 }
8502 zend_ast *value_param_ast = param_list->child[0];
8503 if (value_param_ast->attr & ZEND_PARAM_REF) {
8504 zend_error_noreturn(E_COMPILE_ERROR, "Parameter $%s of %s hook %s::$%s must not be pass-by-reference",
8505 ZSTR_VAL(zend_ast_get_str(value_param_ast->child[1])), ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
8506 }
8507 if (value_param_ast->attr & ZEND_PARAM_VARIADIC) {
8508 zend_error_noreturn(E_COMPILE_ERROR, "Parameter $%s of %s hook %s::$%s must not be variadic",
8509 ZSTR_VAL(zend_ast_get_str(value_param_ast->child[1])), ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
8510 }
8511 if (value_param_ast->child[2]) {
8512 zend_error_noreturn(E_COMPILE_ERROR, "Parameter $%s of %s hook %s::$%s must not have a default value",
8513 ZSTR_VAL(zend_ast_get_str(value_param_ast->child[1])), ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
8514 }
8515 if ((prop_type_ast != NULL) != (value_param_ast->child[0] != NULL)) {
8516 zend_hooked_property_variance_error_ex(zend_ast_get_str(value_param_ast->child[1]), ce->name, prop_info->name);
8517 }
8518 } else {
8519 zend_ast *param_name_ast = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_VALUE));
8520 zend_ast *param = zend_ast_create(
8521 ZEND_AST_PARAM, prop_type_ast, param_name_ast,
8522 /* expr */ NULL, /* doc_comment */ NULL, /* attributes */ NULL,
8523 /* hooks */ NULL);
8524 value_type_ast_ptr = ¶m->child[0];
8525 hook->child[0] = zend_ast_create_list(1, ZEND_AST_PARAM_LIST, param);
8526 }
8527 zend_ast *return_type = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_VOID));
8528 return_type->attr = ZEND_NAME_NOT_FQ;
8529 hook->child[3] = return_type;
8530 } else {
8531 ZEND_UNREACHABLE();
8532 }
8533
8534 hook->name = zend_strpprintf(0, "$%s::%s", ZSTR_VAL(prop_name), ZSTR_VAL(name));
8535
8536 zend_function *func = (zend_function *) zend_compile_func_decl_ex(
8537 NULL, (zend_ast *) hook, /* toplevel */ false, prop_info, hook_kind);
8538
8539 func->common.prop_info = prop_info;
8540
8541 if (!prop_info->hooks) {
8542 prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
8543 memset(prop_info->hooks, 0, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
8544 }
8545
8546 if (prop_info->hooks[hook_kind]) {
8547 zend_error_noreturn(E_COMPILE_ERROR,
8548 "Cannot redeclare property hook \"%s\"", ZSTR_VAL(name));
8549 }
8550 prop_info->hooks[hook_kind] = func;
8551
8552 if (hook_kind == ZEND_PROPERTY_HOOK_SET) {
8553 switch (zend_verify_property_hook_variance(prop_info, func)) {
8554 case INHERITANCE_SUCCESS:
8555 break;
8556 case INHERITANCE_UNRESOLVED:
8557 ce->num_hooked_prop_variance_checks++;
8558 break;
8559 case INHERITANCE_ERROR:
8560 zend_hooked_property_variance_error(prop_info);
8561 case INHERITANCE_WARNING:
8562 ZEND_UNREACHABLE();
8563 }
8564 }
8565
8566 zend_string_release(name);
8567 /* Un-share type ASTs to avoid double-frees of zval nodes. */
8568 if (return_type_ast_ptr) {
8569 *return_type_ast_ptr = NULL;
8570 }
8571 if (value_type_ast_ptr) {
8572 *value_type_ast_ptr = NULL;
8573 }
8574 }
8575
8576 ce->num_hooked_props++;
8577
8578 if (!ce->get_iterator) {
8579 /* Will be removed again, in case of Iterator or IteratorAggregate. */
8580 ce->get_iterator = zend_hooked_object_get_iterator;
8581 }
8582
8583 if (!prop_info->ce->parent_name) {
8584 zend_verify_hooked_property(ce, prop_info, prop_name);
8585 }
8586 }
8587
zend_compile_prop_decl(zend_ast * ast,zend_ast * type_ast,uint32_t flags,zend_ast * attr_ast)8588 static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, zend_ast *attr_ast) /* {{{ */
8589 {
8590 zend_ast_list *list = zend_ast_get_list(ast);
8591 zend_class_entry *ce = CG(active_class_entry);
8592 uint32_t i, children = list->children;
8593
8594 if (ce->ce_flags & ZEND_ACC_ENUM) {
8595 zend_error_noreturn(E_COMPILE_ERROR, "Enum %s cannot include properties", ZSTR_VAL(ce->name));
8596 }
8597
8598 if ((flags & ZEND_ACC_FINAL) && (flags & ZEND_ACC_PRIVATE)) {
8599 zend_error_noreturn(E_COMPILE_ERROR, "Property cannot be both final and private");
8600 }
8601
8602 if ((flags & ZEND_ACC_STATIC) && (flags & ZEND_ACC_PPP_SET_MASK)) {
8603 zend_error_noreturn(E_COMPILE_ERROR, "Static property may not have asymmetric visibility");
8604 }
8605
8606 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
8607 if (flags & ZEND_ACC_FINAL) {
8608 zend_error_noreturn(E_COMPILE_ERROR, "Property in interface cannot be final");
8609 }
8610 if (flags & (ZEND_ACC_PROTECTED|ZEND_ACC_PRIVATE)) {
8611 zend_error_noreturn(E_COMPILE_ERROR, "Property in interface cannot be protected or private");
8612 }
8613 if (flags & ZEND_ACC_ABSTRACT) {
8614 zend_error_noreturn(E_COMPILE_ERROR,
8615 "Property in interface cannot be explicitly abstract. "
8616 "All interface members are implicitly abstract");
8617 }
8618 flags |= ZEND_ACC_ABSTRACT;
8619 }
8620
8621 for (i = 0; i < children; ++i) {
8622 zend_property_info *info;
8623 zend_ast *prop_ast = list->child[i];
8624 zend_ast *name_ast = prop_ast->child[0];
8625 zend_ast **value_ast_ptr = &prop_ast->child[1];
8626 zend_ast *doc_comment_ast = prop_ast->child[2];
8627 zend_ast *hooks_ast = prop_ast->child[3];
8628 zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast));
8629 zend_string *doc_comment = NULL;
8630 zval value_zv;
8631 zend_type type = ZEND_TYPE_INIT_NONE(0);
8632 flags |= zend_property_is_virtual(ce, name, hooks_ast, flags) ? ZEND_ACC_VIRTUAL : 0;
8633
8634 if (!hooks_ast) {
8635 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
8636 zend_error_noreturn(E_COMPILE_ERROR,
8637 "Interfaces may only include hooked properties");
8638 }
8639 if (flags & ZEND_ACC_ABSTRACT) {
8640 zend_error_noreturn(E_COMPILE_ERROR,
8641 "Only hooked properties may be declared abstract");
8642 }
8643 }
8644 if ((flags & ZEND_ACC_ABSTRACT)) {
8645 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
8646 }
8647
8648 if (type_ast) {
8649 type = zend_compile_typename(type_ast);
8650
8651 if (ZEND_TYPE_FULL_MASK(type) & (MAY_BE_VOID|MAY_BE_NEVER|MAY_BE_CALLABLE)) {
8652 zend_string *str = zend_type_to_string(type);
8653 zend_error_noreturn(E_COMPILE_ERROR,
8654 "Property %s::$%s cannot have type %s",
8655 ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(str));
8656 }
8657 }
8658
8659 /* Doc comment has been appended as last element in ZEND_AST_PROP_ELEM ast */
8660 if (doc_comment_ast) {
8661 doc_comment = zend_string_copy(zend_ast_get_str(doc_comment_ast));
8662 }
8663
8664 if (zend_hash_exists(&ce->properties_info, name)) {
8665 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::$%s",
8666 ZSTR_VAL(ce->name), ZSTR_VAL(name));
8667 }
8668
8669 if (*value_ast_ptr) {
8670 zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ false);
8671
8672 if (ZEND_TYPE_IS_SET(type) && !Z_CONSTANT(value_zv)
8673 && !zend_is_valid_default_value(type, &value_zv)) {
8674 zend_string *str = zend_type_to_string(type);
8675 if (Z_TYPE(value_zv) == IS_NULL && !ZEND_TYPE_IS_INTERSECTION(type)) {
8676 ZEND_TYPE_FULL_MASK(type) |= MAY_BE_NULL;
8677 zend_string *nullable_str = zend_type_to_string(type);
8678
8679 zend_error_noreturn(E_COMPILE_ERROR,
8680 "Default value for property of type %s may not be null. "
8681 "Use the nullable type %s to allow null default value",
8682 ZSTR_VAL(str), ZSTR_VAL(nullable_str));
8683 } else {
8684 zend_error_noreturn(E_COMPILE_ERROR,
8685 "Cannot use %s as default value for property %s::$%s of type %s",
8686 zend_zval_value_name(&value_zv),
8687 ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(str));
8688 }
8689 }
8690 } else if (!ZEND_TYPE_IS_SET(type) && !hooks_ast) {
8691 ZVAL_NULL(&value_zv);
8692 } else {
8693 ZVAL_UNDEF(&value_zv);
8694 }
8695
8696 if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS)) {
8697 flags |= ZEND_ACC_READONLY;
8698 }
8699
8700 if (flags & ZEND_ACC_READONLY) {
8701 if (!ZEND_TYPE_IS_SET(type)) {
8702 zend_error_noreturn(E_COMPILE_ERROR, "Readonly property %s::$%s must have type",
8703 ZSTR_VAL(ce->name), ZSTR_VAL(name));
8704 }
8705 if (!Z_ISUNDEF(value_zv)) {
8706 zend_error_noreturn(E_COMPILE_ERROR,
8707 "Readonly property %s::$%s cannot have default value",
8708 ZSTR_VAL(ce->name), ZSTR_VAL(name));
8709 }
8710 if (flags & ZEND_ACC_STATIC) {
8711 zend_error_noreturn(E_COMPILE_ERROR,
8712 "Static property %s::$%s cannot be readonly",
8713 ZSTR_VAL(ce->name), ZSTR_VAL(name));
8714 }
8715 }
8716
8717 info = zend_declare_typed_property(ce, name, &value_zv, flags, doc_comment, type);
8718
8719 if (hooks_ast) {
8720 zend_compile_property_hooks(info, name, type_ast, zend_ast_get_list(hooks_ast));
8721 }
8722
8723 if (attr_ast) {
8724 zend_compile_attributes(&info->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, 0);
8725 }
8726 }
8727 }
8728 /* }}} */
8729
zend_compile_prop_group(zend_ast * ast)8730 static void zend_compile_prop_group(zend_ast *ast) /* {{{ */
8731 {
8732 zend_ast *type_ast = ast->child[0];
8733 zend_ast *prop_ast = ast->child[1];
8734 zend_ast *attr_ast = ast->child[2];
8735
8736 zend_compile_prop_decl(prop_ast, type_ast, ast->attr, attr_ast);
8737 }
8738 /* }}} */
8739
zend_check_trait_alias_modifiers(uint32_t attr)8740 static void zend_check_trait_alias_modifiers(uint32_t attr) /* {{{ */
8741 {
8742 if (attr & ZEND_ACC_STATIC) {
8743 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"static\" as method modifier in trait alias");
8744 } else if (attr & ZEND_ACC_ABSTRACT) {
8745 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"abstract\" as method modifier in trait alias");
8746 }
8747 }
8748 /* }}} */
8749
zend_compile_class_const_decl(zend_ast * ast,uint32_t flags,zend_ast * attr_ast,zend_ast * type_ast)8750 static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast, zend_ast *type_ast)
8751 {
8752 zend_ast_list *list = zend_ast_get_list(ast);
8753 zend_class_entry *ce = CG(active_class_entry);
8754 uint32_t i, children = list->children;
8755
8756 for (i = 0; i < children; ++i) {
8757 zend_class_constant *c;
8758 zend_ast *const_ast = list->child[i];
8759 zend_ast *name_ast = const_ast->child[0];
8760 zend_ast **value_ast_ptr = &const_ast->child[1];
8761 zend_ast *doc_comment_ast = const_ast->child[2];
8762 zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast));
8763 zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
8764 zval value_zv;
8765 zend_type type = ZEND_TYPE_INIT_NONE(0);
8766
8767 if (type_ast) {
8768 type = zend_compile_typename(type_ast);
8769
8770 uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
8771
8772 if (type_mask != MAY_BE_ANY && (type_mask & (MAY_BE_CALLABLE|MAY_BE_VOID|MAY_BE_NEVER))) {
8773 zend_string *type_str = zend_type_to_string(type);
8774
8775 zend_error_noreturn(E_COMPILE_ERROR, "Class constant %s::%s cannot have type %s",
8776 ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(type_str));
8777 }
8778 }
8779
8780 if (UNEXPECTED((flags & ZEND_ACC_PRIVATE) && (flags & ZEND_ACC_FINAL))) {
8781 zend_error_noreturn(
8782 E_COMPILE_ERROR, "Private constant %s::%s cannot be final as it is not visible to other classes",
8783 ZSTR_VAL(ce->name), ZSTR_VAL(name)
8784 );
8785 }
8786
8787 zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ false);
8788
8789 if (!Z_CONSTANT(value_zv) && ZEND_TYPE_IS_SET(type) && !zend_is_valid_default_value(type, &value_zv)) {
8790 zend_string *type_str = zend_type_to_string(type);
8791
8792 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as value for class constant %s::%s of type %s",
8793 zend_zval_type_name(&value_zv), ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(type_str));
8794 }
8795
8796 c = zend_declare_typed_class_constant(ce, name, &value_zv, flags, doc_comment, type);
8797
8798 if (attr_ast) {
8799 zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
8800
8801 zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
8802
8803 if (deprecated) {
8804 ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
8805 }
8806 }
8807 }
8808 }
8809
zend_compile_class_const_group(zend_ast * ast)8810 static void zend_compile_class_const_group(zend_ast *ast) /* {{{ */
8811 {
8812 zend_ast *const_ast = ast->child[0];
8813 zend_ast *attr_ast = ast->child[1];
8814 zend_ast *type_ast = ast->child[2];
8815
8816 zend_compile_class_const_decl(const_ast, ast->attr, attr_ast, type_ast);
8817 }
8818 /* }}} */
8819
zend_compile_method_ref(zend_ast * ast,zend_trait_method_reference * method_ref)8820 static void zend_compile_method_ref(zend_ast *ast, zend_trait_method_reference *method_ref) /* {{{ */
8821 {
8822 zend_ast *class_ast = ast->child[0];
8823 zend_ast *method_ast = ast->child[1];
8824
8825 method_ref->method_name = zend_string_copy(zend_ast_get_str(method_ast));
8826
8827 if (class_ast) {
8828 method_ref->class_name = zend_resolve_const_class_name_reference(class_ast, "trait name");
8829 } else {
8830 method_ref->class_name = NULL;
8831 }
8832 }
8833 /* }}} */
8834
zend_compile_trait_precedence(zend_ast * ast)8835 static void zend_compile_trait_precedence(zend_ast *ast) /* {{{ */
8836 {
8837 zend_ast *method_ref_ast = ast->child[0];
8838 zend_ast *insteadof_ast = ast->child[1];
8839 zend_ast_list *insteadof_list = zend_ast_get_list(insteadof_ast);
8840 uint32_t i;
8841
8842 zend_trait_precedence *precedence = emalloc(sizeof(zend_trait_precedence) + (insteadof_list->children - 1) * sizeof(zend_string*));
8843 zend_compile_method_ref(method_ref_ast, &precedence->trait_method);
8844 precedence->num_excludes = insteadof_list->children;
8845
8846 for (i = 0; i < insteadof_list->children; ++i) {
8847 zend_ast *name_ast = insteadof_list->child[i];
8848 precedence->exclude_class_names[i] =
8849 zend_resolve_const_class_name_reference(name_ast, "trait name");
8850 }
8851
8852 zend_add_to_list(&CG(active_class_entry)->trait_precedences, precedence);
8853 }
8854 /* }}} */
8855
zend_compile_trait_alias(zend_ast * ast)8856 static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
8857 {
8858 zend_ast *method_ref_ast = ast->child[0];
8859 zend_ast *alias_ast = ast->child[1];
8860 uint32_t modifiers = ast->attr;
8861
8862 zend_trait_alias *alias;
8863
8864 zend_check_trait_alias_modifiers(modifiers);
8865
8866 alias = emalloc(sizeof(zend_trait_alias));
8867 zend_compile_method_ref(method_ref_ast, &alias->trait_method);
8868 alias->modifiers = modifiers;
8869
8870 if (alias_ast) {
8871 alias->alias = zend_string_copy(zend_ast_get_str(alias_ast));
8872 } else {
8873 alias->alias = NULL;
8874 }
8875
8876 zend_add_to_list(&CG(active_class_entry)->trait_aliases, alias);
8877 }
8878 /* }}} */
8879
zend_compile_use_trait(zend_ast * ast)8880 static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
8881 {
8882 zend_ast_list *traits = zend_ast_get_list(ast->child[0]);
8883 zend_ast_list *adaptations = ast->child[1] ? zend_ast_get_list(ast->child[1]) : NULL;
8884 zend_class_entry *ce = CG(active_class_entry);
8885 uint32_t i;
8886
8887 ce->trait_names = erealloc(ce->trait_names, sizeof(zend_class_name) * (ce->num_traits + traits->children));
8888
8889 for (i = 0; i < traits->children; ++i) {
8890 zend_ast *trait_ast = traits->child[i];
8891
8892 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
8893 zend_string *name = zend_ast_get_str(trait_ast);
8894 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use traits inside of interfaces. "
8895 "%s is used in %s", ZSTR_VAL(name), ZSTR_VAL(ce->name));
8896 }
8897
8898 ce->trait_names[ce->num_traits].name =
8899 zend_resolve_const_class_name_reference(trait_ast, "trait name");
8900 ce->trait_names[ce->num_traits].lc_name = zend_string_tolower(ce->trait_names[ce->num_traits].name);
8901 ce->num_traits++;
8902 }
8903
8904 if (!adaptations) {
8905 return;
8906 }
8907
8908 for (i = 0; i < adaptations->children; ++i) {
8909 zend_ast *adaptation_ast = adaptations->child[i];
8910 switch (adaptation_ast->kind) {
8911 case ZEND_AST_TRAIT_PRECEDENCE:
8912 zend_compile_trait_precedence(adaptation_ast);
8913 break;
8914 case ZEND_AST_TRAIT_ALIAS:
8915 zend_compile_trait_alias(adaptation_ast);
8916 break;
8917 EMPTY_SWITCH_DEFAULT_CASE()
8918 }
8919 }
8920 }
8921 /* }}} */
8922
zend_compile_implements(zend_ast * ast)8923 static void zend_compile_implements(zend_ast *ast) /* {{{ */
8924 {
8925 zend_ast_list *list = zend_ast_get_list(ast);
8926 zend_class_entry *ce = CG(active_class_entry);
8927 zend_class_name *interface_names;
8928 uint32_t i;
8929
8930 interface_names = emalloc(sizeof(zend_class_name) * list->children);
8931
8932 for (i = 0; i < list->children; ++i) {
8933 zend_ast *class_ast = list->child[i];
8934 interface_names[i].name =
8935 zend_resolve_const_class_name_reference(class_ast, "interface name");
8936 interface_names[i].lc_name = zend_string_tolower(interface_names[i].name);
8937 }
8938
8939 ce->num_interfaces = list->children;
8940 ce->interface_names = interface_names;
8941 }
8942 /* }}} */
8943
zend_generate_anon_class_name(zend_ast_decl * decl)8944 static zend_string *zend_generate_anon_class_name(zend_ast_decl *decl)
8945 {
8946 zend_string *filename = CG(active_op_array)->filename;
8947 uint32_t start_lineno = decl->start_lineno;
8948
8949 /* Use parent or first interface as prefix. */
8950 zend_string *prefix = ZSTR_KNOWN(ZEND_STR_CLASS);
8951 if (decl->child[0]) {
8952 prefix = zend_resolve_const_class_name_reference(decl->child[0], "class name");
8953 } else if (decl->child[1]) {
8954 zend_ast_list *list = zend_ast_get_list(decl->child[1]);
8955 prefix = zend_resolve_const_class_name_reference(list->child[0], "interface name");
8956 }
8957
8958 zend_string *result = zend_strpprintf(0, "%s@anonymous%c%s:%" PRIu32 "$%" PRIx32,
8959 ZSTR_VAL(prefix), '\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
8960 zend_string_release(prefix);
8961 return zend_new_interned_string(result);
8962 }
8963
zend_compile_enum_backing_type(zend_class_entry * ce,zend_ast * enum_backing_type_ast)8964 static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_backing_type_ast)
8965 {
8966 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_ENUM);
8967 zend_type type = zend_compile_typename(enum_backing_type_ast);
8968 uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
8969 if (ZEND_TYPE_IS_COMPLEX(type) || (type_mask != MAY_BE_LONG && type_mask != MAY_BE_STRING)) {
8970 zend_string *type_string = zend_type_to_string(type);
8971 zend_error_noreturn(E_COMPILE_ERROR,
8972 "Enum backing type must be int or string, %s given",
8973 ZSTR_VAL(type_string));
8974 }
8975 if (type_mask == MAY_BE_LONG) {
8976 ce->enum_backing_type = IS_LONG;
8977 } else {
8978 ZEND_ASSERT(type_mask == MAY_BE_STRING);
8979 ce->enum_backing_type = IS_STRING;
8980 }
8981 zend_type_release(type, 0);
8982 }
8983
zend_compile_class_decl(znode * result,zend_ast * ast,bool toplevel)8984 static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{ */
8985 {
8986 zend_ast_decl *decl = (zend_ast_decl *) ast;
8987 zend_ast *extends_ast = decl->child[0];
8988 zend_ast *implements_ast = decl->child[1];
8989 zend_ast *stmt_ast = decl->child[2];
8990 zend_ast *enum_backing_type_ast = decl->child[4];
8991 zend_string *name, *lcname;
8992 zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
8993 zend_op *opline;
8994
8995 zend_class_entry *original_ce = CG(active_class_entry);
8996
8997 if (EXPECTED((decl->flags & ZEND_ACC_ANON_CLASS) == 0)) {
8998 zend_string *unqualified_name = decl->name;
8999
9000 if (CG(active_class_entry)) {
9001 zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
9002 }
9003
9004 const char *type = "a class name";
9005 if (decl->flags & ZEND_ACC_ENUM) {
9006 type = "an enum name";
9007 } else if (decl->flags & ZEND_ACC_INTERFACE) {
9008 type = "an interface name";
9009 } else if (decl->flags & ZEND_ACC_TRAIT) {
9010 type = "a trait name";
9011 }
9012 zend_assert_valid_class_name(unqualified_name, type);
9013 name = zend_prefix_with_ns(unqualified_name);
9014 name = zend_new_interned_string(name);
9015 lcname = zend_string_tolower(name);
9016
9017 if (FC(imports)) {
9018 zend_string *import_name =
9019 zend_hash_find_ptr_lc(FC(imports), unqualified_name);
9020 if (import_name && !zend_string_equals_ci(lcname, import_name)) {
9021 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare class %s "
9022 "(previously declared as local import)", ZSTR_VAL(name));
9023 }
9024 }
9025
9026 zend_register_seen_symbol(lcname, ZEND_SYMBOL_CLASS);
9027 } else {
9028 /* Find an anon class name that is not in use yet. */
9029 name = NULL;
9030 lcname = NULL;
9031 do {
9032 zend_tmp_string_release(name);
9033 zend_tmp_string_release(lcname);
9034 name = zend_generate_anon_class_name(decl);
9035 lcname = zend_string_tolower(name);
9036 } while (zend_hash_exists(CG(class_table), lcname));
9037 }
9038 lcname = zend_new_interned_string(lcname);
9039
9040 ce->type = ZEND_USER_CLASS;
9041 ce->name = name;
9042 zend_initialize_class_data(ce, 1);
9043 if (!(decl->flags & ZEND_ACC_ANON_CLASS)) {
9044 zend_alloc_ce_cache(ce->name);
9045 }
9046
9047 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
9048 ce->ce_flags |= ZEND_ACC_PRELOADED;
9049 ZEND_MAP_PTR_NEW(ce->static_members_table);
9050 ZEND_MAP_PTR_NEW(ce->mutable_data);
9051 }
9052
9053 ce->ce_flags |= decl->flags;
9054 ce->info.user.filename = zend_string_copy(zend_get_compiled_filename());
9055 ce->info.user.line_start = decl->start_lineno;
9056 ce->info.user.line_end = decl->end_lineno;
9057
9058 if (decl->doc_comment) {
9059 ce->doc_comment = zend_string_copy(decl->doc_comment);
9060 }
9061
9062 if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) {
9063 /* Serialization is not supported for anonymous classes */
9064 ce->ce_flags |= ZEND_ACC_NOT_SERIALIZABLE;
9065 }
9066
9067 if (extends_ast) {
9068 ce->parent_name =
9069 zend_resolve_const_class_name_reference(extends_ast, "class name");
9070 }
9071
9072 CG(active_class_entry) = ce;
9073
9074 if (decl->child[3]) {
9075 zend_compile_attributes(&ce->attributes, decl->child[3], 0, ZEND_ATTRIBUTE_TARGET_CLASS, 0);
9076 }
9077
9078 if (implements_ast) {
9079 zend_compile_implements(implements_ast);
9080 }
9081
9082 if (ce->ce_flags & ZEND_ACC_ENUM) {
9083 if (enum_backing_type_ast != NULL) {
9084 zend_compile_enum_backing_type(ce, enum_backing_type_ast);
9085 }
9086 zend_enum_add_interfaces(ce);
9087 zend_enum_register_props(ce);
9088 }
9089
9090 zend_compile_stmt(stmt_ast);
9091
9092 /* Reset lineno for final opcodes and errors */
9093 CG(zend_lineno) = ast->lineno;
9094
9095 if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
9096 zend_verify_abstract_class(ce);
9097 }
9098
9099 CG(active_class_entry) = original_ce;
9100
9101 if (toplevel) {
9102 ce->ce_flags |= ZEND_ACC_TOP_LEVEL;
9103 }
9104
9105 /* We currently don't early-bind classes that implement interfaces or use traits */
9106 if (!ce->num_interfaces && !ce->num_traits && !ce->num_hooked_prop_variance_checks
9107 && !(CG(compiler_options) & ZEND_COMPILE_WITHOUT_EXECUTION)) {
9108 if (toplevel) {
9109 if (extends_ast) {
9110 zend_class_entry *parent_ce = zend_lookup_class_ex(
9111 ce->parent_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
9112
9113 if (parent_ce
9114 && !zend_compile_ignore_class(parent_ce, ce->info.user.filename)) {
9115 if (zend_try_early_bind(ce, parent_ce, lcname, NULL)) {
9116 zend_string_release(lcname);
9117 return;
9118 }
9119 }
9120 } else if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) {
9121 zend_string_release(lcname);
9122 zend_build_properties_info_table(ce);
9123 zend_inheritance_check_override(ce);
9124 ce->ce_flags |= ZEND_ACC_LINKED;
9125 zend_observer_class_linked_notify(ce, lcname);
9126 return;
9127 } else {
9128 goto link_unbound;
9129 }
9130 } else if (!extends_ast) {
9131 link_unbound:
9132 /* Link unbound simple class */
9133 zend_build_properties_info_table(ce);
9134 zend_inheritance_check_override(ce);
9135 ce->ce_flags |= ZEND_ACC_LINKED;
9136 }
9137 }
9138
9139 opline = get_next_op();
9140
9141 if (ce->parent_name) {
9142 /* Lowercased parent name */
9143 zend_string *lc_parent_name = zend_string_tolower(ce->parent_name);
9144 opline->op2_type = IS_CONST;
9145 LITERAL_STR(opline->op2, lc_parent_name);
9146 }
9147
9148 opline->op1_type = IS_CONST;
9149 /* It's possible that `lcname` is not an interned string because it was not yet in the interned string table.
9150 * However, by this point another thread may have caused `lcname` to be added in the interned string table.
9151 * This will cause `lcname` to get freed once it is found in the interned string table. If we were to use
9152 * LITERAL_STR() here we would not change the `lcname` pointer to the new value, and it would point to the
9153 * now-freed string. This will cause issues when we use `lcname` in the code below. We solve this by using
9154 * zend_add_literal_string() which gives us the new value. */
9155 opline->op1.constant = zend_add_literal_string(&lcname);
9156
9157 if (decl->flags & ZEND_ACC_ANON_CLASS) {
9158 opline->opcode = ZEND_DECLARE_ANON_CLASS;
9159 opline->extended_value = zend_alloc_cache_slot();
9160 zend_make_var_result(result, opline);
9161 if (!zend_hash_add_ptr(CG(class_table), lcname, ce)) {
9162 /* We checked above that the class name is not used. This really shouldn't happen. */
9163 zend_error_noreturn(E_ERROR,
9164 "Runtime definition key collision for %s. This is a bug", ZSTR_VAL(name));
9165 }
9166 } else {
9167 /* Generate RTD keys until we find one that isn't in use yet. */
9168 zend_string *key = NULL;
9169 do {
9170 zend_tmp_string_release(key);
9171 key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
9172 } while (!zend_hash_add_ptr(CG(class_table), key, ce));
9173
9174 /* RTD key is placed after lcname literal in op1 */
9175 zend_add_literal_string(&key);
9176
9177 opline->opcode = ZEND_DECLARE_CLASS;
9178 if (toplevel
9179 && (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING)
9180 /* We currently don't early-bind classes that implement interfaces or use traits */
9181 && !ce->num_interfaces && !ce->num_traits && !ce->num_hooked_prop_variance_checks
9182 ) {
9183 if (!extends_ast) {
9184 /* Use empty string for classes without parents to avoid new handler, and special
9185 * handling of zend_early_binding. */
9186 opline->op2_type = IS_CONST;
9187 LITERAL_STR(opline->op2, ZSTR_EMPTY_ALLOC());
9188 }
9189 CG(active_op_array)->fn_flags |= ZEND_ACC_EARLY_BINDING;
9190 opline->opcode = ZEND_DECLARE_CLASS_DELAYED;
9191 opline->extended_value = zend_alloc_cache_slot();
9192 opline->result_type = IS_UNUSED;
9193 opline->result.opline_num = -1;
9194 }
9195 }
9196 }
9197 /* }}} */
9198
zend_compile_enum_case(zend_ast * ast)9199 static void zend_compile_enum_case(zend_ast *ast)
9200 {
9201 zend_class_entry *enum_class = CG(active_class_entry);
9202 if (!(enum_class->ce_flags & ZEND_ACC_ENUM)) {
9203 zend_error_noreturn(E_COMPILE_ERROR, "Case can only be used in enums");
9204 }
9205
9206 zend_string *enum_case_name = zval_make_interned_string(zend_ast_get_zval(ast->child[0]));
9207 zend_string *enum_class_name = enum_class->name;
9208
9209 zval class_name_zval;
9210 ZVAL_STR_COPY(&class_name_zval, enum_class_name);
9211 zend_ast *class_name_ast = zend_ast_create_zval(&class_name_zval);
9212
9213 zval case_name_zval;
9214 ZVAL_STR_COPY(&case_name_zval, enum_case_name);
9215 zend_ast *case_name_ast = zend_ast_create_zval(&case_name_zval);
9216
9217 zend_ast *case_value_ast = ast->child[1];
9218 // Remove case_value_ast from the original AST to avoid freeing it, as it will be freed by zend_const_expr_to_zval
9219 ast->child[1] = NULL;
9220 if (enum_class->enum_backing_type != IS_UNDEF && case_value_ast == NULL) {
9221 zend_error_noreturn(E_COMPILE_ERROR, "Case %s of backed enum %s must have a value",
9222 ZSTR_VAL(enum_case_name),
9223 ZSTR_VAL(enum_class_name));
9224 } else if (enum_class->enum_backing_type == IS_UNDEF && case_value_ast != NULL) {
9225 zend_error_noreturn(E_COMPILE_ERROR, "Case %s of non-backed enum %s must not have a value",
9226 ZSTR_VAL(enum_case_name),
9227 ZSTR_VAL(enum_class_name));
9228 }
9229
9230 zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, class_name_ast, case_name_ast, case_value_ast);
9231
9232 zval value_zv;
9233 zend_const_expr_to_zval(&value_zv, &const_enum_init_ast, /* allow_dynamic */ false);
9234
9235 /* Doc comment has been appended as second last element in ZEND_AST_ENUM ast - attributes are conventionally last */
9236 zend_ast *doc_comment_ast = ast->child[2];
9237 zend_string *doc_comment = NULL;
9238 if (doc_comment_ast) {
9239 doc_comment = zend_string_copy(zend_ast_get_str(doc_comment_ast));
9240 }
9241
9242 zend_class_constant *c = zend_declare_class_constant_ex(enum_class, enum_case_name, &value_zv, ZEND_ACC_PUBLIC, doc_comment);
9243 ZEND_CLASS_CONST_FLAGS(c) |= ZEND_CLASS_CONST_IS_CASE;
9244 zend_ast_destroy(const_enum_init_ast);
9245
9246 zend_ast *attr_ast = ast->child[3];
9247 if (attr_ast) {
9248 zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
9249
9250 zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
9251
9252 if (deprecated) {
9253 ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
9254 }
9255 }
9256 }
9257
zend_get_import_ht(uint32_t type)9258 static HashTable *zend_get_import_ht(uint32_t type) /* {{{ */
9259 {
9260 switch (type) {
9261 case ZEND_SYMBOL_CLASS:
9262 if (!FC(imports)) {
9263 FC(imports) = emalloc(sizeof(HashTable));
9264 zend_hash_init(FC(imports), 8, NULL, str_dtor, 0);
9265 }
9266 return FC(imports);
9267 case ZEND_SYMBOL_FUNCTION:
9268 if (!FC(imports_function)) {
9269 FC(imports_function) = emalloc(sizeof(HashTable));
9270 zend_hash_init(FC(imports_function), 8, NULL, str_dtor, 0);
9271 }
9272 return FC(imports_function);
9273 case ZEND_SYMBOL_CONST:
9274 if (!FC(imports_const)) {
9275 FC(imports_const) = emalloc(sizeof(HashTable));
9276 zend_hash_init(FC(imports_const), 8, NULL, str_dtor, 0);
9277 }
9278 return FC(imports_const);
9279 EMPTY_SWITCH_DEFAULT_CASE()
9280 }
9281
9282 return NULL;
9283 }
9284 /* }}} */
9285
zend_get_use_type_str(uint32_t type)9286 static char *zend_get_use_type_str(uint32_t type) /* {{{ */
9287 {
9288 switch (type) {
9289 case ZEND_SYMBOL_CLASS:
9290 return "";
9291 case ZEND_SYMBOL_FUNCTION:
9292 return " function";
9293 case ZEND_SYMBOL_CONST:
9294 return " const";
9295 EMPTY_SWITCH_DEFAULT_CASE()
9296 }
9297
9298 return " unknown";
9299 }
9300 /* }}} */
9301
zend_check_already_in_use(uint32_t type,zend_string * old_name,zend_string * new_name,zend_string * check_name)9302 static void zend_check_already_in_use(uint32_t type, zend_string *old_name, zend_string *new_name, zend_string *check_name) /* {{{ */
9303 {
9304 if (zend_string_equals_ci(old_name, check_name)) {
9305 return;
9306 }
9307
9308 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use%s %s as %s because the name "
9309 "is already in use", zend_get_use_type_str(type), ZSTR_VAL(old_name), ZSTR_VAL(new_name));
9310 }
9311 /* }}} */
9312
zend_compile_use(zend_ast * ast)9313 static void zend_compile_use(zend_ast *ast) /* {{{ */
9314 {
9315 zend_ast_list *list = zend_ast_get_list(ast);
9316 uint32_t i;
9317 zend_string *current_ns = FC(current_namespace);
9318 uint32_t type = ast->attr;
9319 HashTable *current_import = zend_get_import_ht(type);
9320 bool case_sensitive = type == ZEND_SYMBOL_CONST;
9321
9322 for (i = 0; i < list->children; ++i) {
9323 zend_ast *use_ast = list->child[i];
9324 zend_ast *old_name_ast = use_ast->child[0];
9325 zend_ast *new_name_ast = use_ast->child[1];
9326 zend_string *old_name = zend_ast_get_str(old_name_ast);
9327 zend_string *new_name, *lookup_name;
9328
9329 if (new_name_ast) {
9330 new_name = zend_string_copy(zend_ast_get_str(new_name_ast));
9331 } else {
9332 const char *unqualified_name;
9333 size_t unqualified_name_len;
9334 if (zend_get_unqualified_name(old_name, &unqualified_name, &unqualified_name_len)) {
9335 /* The form "use A\B" is equivalent to "use A\B as B" */
9336 new_name = zend_string_init(unqualified_name, unqualified_name_len, 0);
9337 } else {
9338 new_name = zend_string_copy(old_name);
9339
9340 if (!current_ns) {
9341 zend_error(E_WARNING, "The use statement with non-compound name '%s' "
9342 "has no effect", ZSTR_VAL(new_name));
9343 }
9344 }
9345 }
9346
9347 if (case_sensitive) {
9348 lookup_name = zend_string_copy(new_name);
9349 } else {
9350 lookup_name = zend_string_tolower(new_name);
9351 }
9352
9353 if (type == ZEND_SYMBOL_CLASS && zend_is_reserved_class_name(new_name)) {
9354 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' "
9355 "is a special class name", ZSTR_VAL(old_name), ZSTR_VAL(new_name), ZSTR_VAL(new_name));
9356 }
9357
9358 if (current_ns) {
9359 zend_string *ns_name = zend_string_alloc(ZSTR_LEN(current_ns) + 1 + ZSTR_LEN(new_name), 0);
9360 zend_str_tolower_copy(ZSTR_VAL(ns_name), ZSTR_VAL(current_ns), ZSTR_LEN(current_ns));
9361 ZSTR_VAL(ns_name)[ZSTR_LEN(current_ns)] = '\\';
9362 memcpy(ZSTR_VAL(ns_name) + ZSTR_LEN(current_ns) + 1, ZSTR_VAL(lookup_name), ZSTR_LEN(lookup_name) + 1);
9363
9364 if (zend_have_seen_symbol(ns_name, type)) {
9365 zend_check_already_in_use(type, old_name, new_name, ns_name);
9366 }
9367
9368 zend_string_efree(ns_name);
9369 } else if (zend_have_seen_symbol(lookup_name, type)) {
9370 zend_check_already_in_use(type, old_name, new_name, lookup_name);
9371 }
9372
9373 zend_string_addref(old_name);
9374 old_name = zend_new_interned_string(old_name);
9375 if (!zend_hash_add_ptr(current_import, lookup_name, old_name)) {
9376 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use%s %s as %s because the name "
9377 "is already in use", zend_get_use_type_str(type), ZSTR_VAL(old_name), ZSTR_VAL(new_name));
9378 }
9379
9380 zend_string_release_ex(lookup_name, 0);
9381 zend_string_release_ex(new_name, 0);
9382 }
9383 }
9384 /* }}} */
9385
zend_compile_group_use(zend_ast * ast)9386 static void zend_compile_group_use(zend_ast *ast) /* {{{ */
9387 {
9388 uint32_t i;
9389 zend_string *ns = zend_ast_get_str(ast->child[0]);
9390 zend_ast_list *list = zend_ast_get_list(ast->child[1]);
9391
9392 for (i = 0; i < list->children; i++) {
9393 zend_ast *inline_use, *use = list->child[i];
9394 zval *name_zval = zend_ast_get_zval(use->child[0]);
9395 zend_string *name = Z_STR_P(name_zval);
9396 zend_string *compound_ns = zend_concat_names(ZSTR_VAL(ns), ZSTR_LEN(ns), ZSTR_VAL(name), ZSTR_LEN(name));
9397 zend_string_release_ex(name, 0);
9398 ZVAL_STR(name_zval, compound_ns);
9399 inline_use = zend_ast_create_list(1, ZEND_AST_USE, use);
9400 inline_use->attr = ast->attr ? ast->attr : use->attr;
9401 zend_compile_use(inline_use);
9402 }
9403 }
9404 /* }}} */
9405
zend_compile_const_decl(zend_ast * ast)9406 static void zend_compile_const_decl(zend_ast *ast) /* {{{ */
9407 {
9408 zend_ast_list *list = zend_ast_get_list(ast);
9409 uint32_t i;
9410 for (i = 0; i < list->children; ++i) {
9411 zend_ast *const_ast = list->child[i];
9412 zend_ast *name_ast = const_ast->child[0];
9413 zend_ast **value_ast_ptr = &const_ast->child[1];
9414 zend_string *unqualified_name = zend_ast_get_str(name_ast);
9415
9416 zend_string *name;
9417 znode name_node, value_node;
9418 zval *value_zv = &value_node.u.constant;
9419
9420 value_node.op_type = IS_CONST;
9421 zend_const_expr_to_zval(value_zv, value_ast_ptr, /* allow_dynamic */ true);
9422
9423 if (zend_get_special_const(ZSTR_VAL(unqualified_name), ZSTR_LEN(unqualified_name))) {
9424 zend_error_noreturn(E_COMPILE_ERROR,
9425 "Cannot redeclare constant '%s'", ZSTR_VAL(unqualified_name));
9426 }
9427
9428 name = zend_prefix_with_ns(unqualified_name);
9429 name = zend_new_interned_string(name);
9430
9431 if (FC(imports_const)) {
9432 zend_string *import_name = zend_hash_find_ptr(FC(imports_const), unqualified_name);
9433 if (import_name && !zend_string_equals(import_name, name)) {
9434 zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare const %s because "
9435 "the name is already in use", ZSTR_VAL(name));
9436 }
9437 }
9438
9439 name_node.op_type = IS_CONST;
9440 ZVAL_STR(&name_node.u.constant, name);
9441
9442 zend_emit_op(NULL, ZEND_DECLARE_CONST, &name_node, &value_node);
9443
9444 zend_register_seen_symbol(name, ZEND_SYMBOL_CONST);
9445 }
9446 }
9447 /* }}}*/
9448
zend_compile_namespace(zend_ast * ast)9449 static void zend_compile_namespace(zend_ast *ast) /* {{{ */
9450 {
9451 zend_ast *name_ast = ast->child[0];
9452 zend_ast *stmt_ast = ast->child[1];
9453 zend_string *name;
9454 bool with_bracket = stmt_ast != NULL;
9455
9456 /* handle mixed syntax declaration or nested namespaces */
9457 if (!FC(has_bracketed_namespaces)) {
9458 if (FC(current_namespace)) {
9459 /* previous namespace declarations were unbracketed */
9460 if (with_bracket) {
9461 zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations "
9462 "with unbracketed namespace declarations");
9463 }
9464 }
9465 } else {
9466 /* previous namespace declarations were bracketed */
9467 if (!with_bracket) {
9468 zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations "
9469 "with unbracketed namespace declarations");
9470 } else if (FC(current_namespace) || FC(in_namespace)) {
9471 zend_error_noreturn(E_COMPILE_ERROR, "Namespace declarations cannot be nested");
9472 }
9473 }
9474
9475 bool is_first_namespace = (!with_bracket && !FC(current_namespace))
9476 || (with_bracket && !FC(has_bracketed_namespaces));
9477 if (is_first_namespace && FAILURE == zend_is_first_statement(ast, /* allow_nop */ 1)) {
9478 zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be "
9479 "the very first statement or after any declare call in the script");
9480 }
9481
9482 if (FC(current_namespace)) {
9483 zend_string_release_ex(FC(current_namespace), 0);
9484 }
9485
9486 if (name_ast) {
9487 name = zend_ast_get_str(name_ast);
9488
9489 if (zend_string_equals_literal_ci(name, "namespace")) {
9490 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", ZSTR_VAL(name));
9491 }
9492
9493 FC(current_namespace) = zend_string_copy(name);
9494 } else {
9495 FC(current_namespace) = NULL;
9496 }
9497
9498 zend_reset_import_tables();
9499
9500 FC(in_namespace) = 1;
9501 if (with_bracket) {
9502 FC(has_bracketed_namespaces) = 1;
9503 }
9504
9505 if (stmt_ast) {
9506 zend_compile_top_stmt(stmt_ast);
9507 zend_end_namespace();
9508 }
9509 }
9510 /* }}} */
9511
zend_compile_halt_compiler(zend_ast * ast)9512 static void zend_compile_halt_compiler(zend_ast *ast) /* {{{ */
9513 {
9514 zend_ast *offset_ast = ast->child[0];
9515 zend_long offset = Z_LVAL_P(zend_ast_get_zval(offset_ast));
9516
9517 zend_string *filename, *name;
9518 const char const_name[] = "__COMPILER_HALT_OFFSET__";
9519
9520 if (FC(has_bracketed_namespaces) && FC(in_namespace)) {
9521 zend_error_noreturn(E_COMPILE_ERROR,
9522 "__HALT_COMPILER() can only be used from the outermost scope");
9523 }
9524
9525 filename = zend_get_compiled_filename();
9526 name = zend_mangle_property_name(const_name, sizeof(const_name) - 1,
9527 ZSTR_VAL(filename), ZSTR_LEN(filename), 0);
9528
9529 zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), offset, 0, 0);
9530 zend_string_release_ex(name, 0);
9531 }
9532 /* }}} */
9533
zend_try_ct_eval_magic_const(zval * zv,zend_ast * ast)9534 static bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast) /* {{{ */
9535 {
9536 zend_op_array *op_array = CG(active_op_array);
9537 zend_class_entry *ce = CG(active_class_entry);
9538
9539 switch (ast->attr) {
9540 case T_LINE:
9541 ZVAL_LONG(zv, ast->lineno);
9542 break;
9543 case T_FILE:
9544 ZVAL_STR_COPY(zv, CG(compiled_filename));
9545 break;
9546 case T_DIR:
9547 {
9548 zend_string *filename = CG(compiled_filename);
9549 zend_string *dirname = zend_string_init(ZSTR_VAL(filename), ZSTR_LEN(filename), 0);
9550 #ifdef ZEND_WIN32
9551 ZSTR_LEN(dirname) = php_win32_ioutil_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
9552 #else
9553 ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
9554 #endif
9555
9556 if (zend_string_equals_literal(dirname, ".")) {
9557 dirname = zend_string_extend(dirname, MAXPATHLEN, 0);
9558 #ifdef HAVE_GETCWD
9559 ZEND_IGNORE_VALUE(VCWD_GETCWD(ZSTR_VAL(dirname), MAXPATHLEN));
9560 #elif defined(HAVE_GETWD)
9561 ZEND_IGNORE_VALUE(VCWD_GETWD(ZSTR_VAL(dirname)));
9562 #endif
9563 ZSTR_LEN(dirname) = strlen(ZSTR_VAL(dirname));
9564 }
9565
9566 ZVAL_STR(zv, dirname);
9567 break;
9568 }
9569 case T_FUNC_C:
9570 if (op_array && op_array->function_name) {
9571 ZVAL_STR_COPY(zv, op_array->function_name);
9572 } else {
9573 ZVAL_EMPTY_STRING(zv);
9574 }
9575 break;
9576 case T_PROPERTY_C: {
9577 const zend_property_info *prop_info = CG(context).active_property_info;
9578 if (prop_info) {
9579 ZVAL_STR(zv, zend_copy_unmangled_prop_name(prop_info->name));
9580 } else {
9581 ZVAL_EMPTY_STRING(zv);
9582 }
9583 break;
9584 }
9585 case T_METHOD_C:
9586 /* Detect whether we are directly inside a class (e.g. a class constant) and treat
9587 * this as not being inside a function. */
9588 if (op_array && ce && !op_array->scope && !(op_array->fn_flags & ZEND_ACC_CLOSURE)) {
9589 op_array = NULL;
9590 }
9591 if (op_array && op_array->function_name) {
9592 if (op_array->scope) {
9593 ZVAL_NEW_STR(zv,
9594 zend_create_member_string(op_array->scope->name, op_array->function_name));
9595 } else {
9596 ZVAL_STR_COPY(zv, op_array->function_name);
9597 }
9598 } else {
9599 ZVAL_EMPTY_STRING(zv);
9600 }
9601 break;
9602 case T_CLASS_C:
9603 if (ce) {
9604 if ((ce->ce_flags & ZEND_ACC_TRAIT) != 0) {
9605 return 0;
9606 } else {
9607 ZVAL_STR_COPY(zv, ce->name);
9608 }
9609 } else {
9610 ZVAL_EMPTY_STRING(zv);
9611 }
9612 break;
9613 case T_TRAIT_C:
9614 if (ce && (ce->ce_flags & ZEND_ACC_TRAIT) != 0) {
9615 ZVAL_STR_COPY(zv, ce->name);
9616 } else {
9617 ZVAL_EMPTY_STRING(zv);
9618 }
9619 break;
9620 case T_NS_C:
9621 if (FC(current_namespace)) {
9622 ZVAL_STR_COPY(zv, FC(current_namespace));
9623 } else {
9624 ZVAL_EMPTY_STRING(zv);
9625 }
9626 break;
9627 EMPTY_SWITCH_DEFAULT_CASE()
9628 }
9629
9630 return 1;
9631 }
9632 /* }}} */
9633
zend_is_op_long_compatible(const zval * op)9634 ZEND_API bool zend_is_op_long_compatible(const zval *op)
9635 {
9636 if (Z_TYPE_P(op) == IS_ARRAY) {
9637 return false;
9638 }
9639
9640 if (Z_TYPE_P(op) == IS_DOUBLE
9641 && !zend_is_long_compatible(Z_DVAL_P(op), zend_dval_to_lval(Z_DVAL_P(op)))) {
9642 return false;
9643 }
9644
9645 if (Z_TYPE_P(op) == IS_STRING) {
9646 double dval = 0;
9647 uint8_t is_num = is_numeric_str_function(Z_STR_P(op), NULL, &dval);
9648 if (is_num == 0 || (is_num == IS_DOUBLE && !zend_is_long_compatible(dval, zend_dval_to_lval(dval)))) {
9649 return false;
9650 }
9651 }
9652
9653 return true;
9654 }
9655
zend_binary_op_produces_error(uint32_t opcode,const zval * op1,const zval * op2)9656 ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, const zval *op1, const zval *op2) /* {{{ */
9657 {
9658 if ((opcode == ZEND_CONCAT || opcode == ZEND_FAST_CONCAT)) {
9659 /* Array to string warning. */
9660 return Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY;
9661 }
9662
9663 if (!(opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_DIV
9664 || opcode == ZEND_POW || opcode == ZEND_MOD || opcode == ZEND_SL || opcode == ZEND_SR
9665 || opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)) {
9666 /* Only the numeric operations throw errors. */
9667 return 0;
9668 }
9669
9670 if (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY) {
9671 if (opcode == ZEND_ADD && Z_TYPE_P(op1) == IS_ARRAY && Z_TYPE_P(op2) == IS_ARRAY) {
9672 /* Adding two arrays is allowed. */
9673 return 0;
9674 }
9675
9676 /* Numeric operators throw when one of the operands is an array. */
9677 return 1;
9678 }
9679
9680 /* While basic arithmetic operators always produce numeric string errors,
9681 * bitwise operators don't produce errors if both operands are strings */
9682 if ((opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)
9683 && Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
9684 return 0;
9685 }
9686
9687 if (Z_TYPE_P(op1) == IS_STRING
9688 && !is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), NULL, NULL, 0)) {
9689 return 1;
9690 }
9691
9692 if (Z_TYPE_P(op2) == IS_STRING
9693 && !is_numeric_string(Z_STRVAL_P(op2), Z_STRLEN_P(op2), NULL, NULL, 0)) {
9694 return 1;
9695 }
9696
9697 if ((opcode == ZEND_MOD && zval_get_long(op2) == 0)
9698 || (opcode == ZEND_DIV && zval_get_double(op2) == 0.0)) {
9699 /* Division by zero throws an error. */
9700 return 1;
9701 }
9702 if ((opcode == ZEND_POW) && zval_get_double(op1) == 0 && zval_get_double(op2) < 0) {
9703 /* 0 ** (<0) throws a division by zero error. */
9704 return 1;
9705 }
9706 if ((opcode == ZEND_SL || opcode == ZEND_SR) && zval_get_long(op2) < 0) {
9707 /* Shift by negative number throws an error. */
9708 return 1;
9709 }
9710
9711 /* Operation which cast float/float-strings to integers might produce incompatible float to int errors */
9712 if (opcode == ZEND_SL || opcode == ZEND_SR || opcode == ZEND_BW_OR
9713 || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR || opcode == ZEND_MOD) {
9714 return !zend_is_op_long_compatible(op1) || !zend_is_op_long_compatible(op2);
9715 }
9716
9717 return 0;
9718 }
9719 /* }}} */
9720
zend_try_ct_eval_binary_op(zval * result,uint32_t opcode,zval * op1,zval * op2)9721 static inline bool zend_try_ct_eval_binary_op(zval *result, uint32_t opcode, zval *op1, zval *op2) /* {{{ */
9722 {
9723 if (zend_binary_op_produces_error(opcode, op1, op2)) {
9724 return 0;
9725 }
9726
9727 binary_op_type fn = get_binary_op(opcode);
9728 fn(result, op1, op2);
9729 return 1;
9730 }
9731 /* }}} */
9732
zend_unary_op_produces_error(uint32_t opcode,const zval * op)9733 ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, const zval *op)
9734 {
9735 if (opcode == ZEND_BW_NOT) {
9736 /* BW_NOT on string does not convert the string into an integer. */
9737 if (Z_TYPE_P(op) == IS_STRING) {
9738 return 0;
9739 }
9740 return Z_TYPE_P(op) <= IS_TRUE || !zend_is_op_long_compatible(op);
9741 }
9742
9743 return 0;
9744 }
9745
zend_try_ct_eval_unary_op(zval * result,uint32_t opcode,zval * op)9746 static inline bool zend_try_ct_eval_unary_op(zval *result, uint32_t opcode, zval *op) /* {{{ */
9747 {
9748 if (zend_unary_op_produces_error(opcode, op)) {
9749 return 0;
9750 }
9751
9752 unary_op_type fn = get_unary_op(opcode);
9753 fn(result, op);
9754 return 1;
9755 }
9756 /* }}} */
9757
zend_try_ct_eval_unary_pm(zval * result,zend_ast_kind kind,zval * op)9758 static inline bool zend_try_ct_eval_unary_pm(zval *result, zend_ast_kind kind, zval *op) /* {{{ */
9759 {
9760 zval right;
9761 ZVAL_LONG(&right, (kind == ZEND_AST_UNARY_PLUS) ? 1 : -1);
9762 return zend_try_ct_eval_binary_op(result, ZEND_MUL, op, &right);
9763 }
9764 /* }}} */
9765
zend_ct_eval_greater(zval * result,zend_ast_kind kind,zval * op1,zval * op2)9766 static inline void zend_ct_eval_greater(zval *result, zend_ast_kind kind, zval *op1, zval *op2) /* {{{ */
9767 {
9768 binary_op_type fn = kind == ZEND_AST_GREATER
9769 ? is_smaller_function : is_smaller_or_equal_function;
9770 fn(result, op2, op1);
9771 }
9772 /* }}} */
9773
zend_try_ct_eval_array(zval * result,zend_ast * ast)9774 static bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */
9775 {
9776 zend_ast_list *list = zend_ast_get_list(ast);
9777 zend_ast *last_elem_ast = NULL;
9778 uint32_t i;
9779 bool is_constant = 1;
9780
9781 if (ast->attr == ZEND_ARRAY_SYNTAX_LIST) {
9782 zend_error(E_COMPILE_ERROR, "Cannot use list() as standalone expression");
9783 }
9784
9785 /* First ensure that *all* child nodes are constant and by-val */
9786 for (i = 0; i < list->children; ++i) {
9787 zend_ast *elem_ast = list->child[i];
9788
9789 if (elem_ast == NULL) {
9790 /* Report error at line of last non-empty element */
9791 if (last_elem_ast) {
9792 CG(zend_lineno) = zend_ast_get_lineno(last_elem_ast);
9793 }
9794 zend_error(E_COMPILE_ERROR, "Cannot use empty array elements in arrays");
9795 }
9796
9797 if (elem_ast->kind != ZEND_AST_UNPACK) {
9798 zend_eval_const_expr(&elem_ast->child[0]);
9799 zend_eval_const_expr(&elem_ast->child[1]);
9800
9801 if (elem_ast->attr /* by_ref */ || elem_ast->child[0]->kind != ZEND_AST_ZVAL
9802 || (elem_ast->child[1] && elem_ast->child[1]->kind != ZEND_AST_ZVAL)
9803 ) {
9804 is_constant = 0;
9805 }
9806 } else {
9807 zend_eval_const_expr(&elem_ast->child[0]);
9808
9809 if (elem_ast->child[0]->kind != ZEND_AST_ZVAL) {
9810 is_constant = 0;
9811 }
9812 }
9813
9814 last_elem_ast = elem_ast;
9815 }
9816
9817 if (!is_constant) {
9818 return 0;
9819 }
9820
9821 if (!list->children) {
9822 ZVAL_EMPTY_ARRAY(result);
9823 return 1;
9824 }
9825
9826 array_init_size(result, list->children);
9827 for (i = 0; i < list->children; ++i) {
9828 zend_ast *elem_ast = list->child[i];
9829 zend_ast *value_ast = elem_ast->child[0];
9830 zend_ast *key_ast;
9831
9832 zval *value = zend_ast_get_zval(value_ast);
9833 if (elem_ast->kind == ZEND_AST_UNPACK) {
9834 if (Z_TYPE_P(value) == IS_ARRAY) {
9835 HashTable *ht = Z_ARRVAL_P(value);
9836 zval *val;
9837 zend_string *key;
9838
9839 ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
9840 if (key) {
9841 zend_hash_update(Z_ARRVAL_P(result), key, val);
9842 } else if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), val)) {
9843 zval_ptr_dtor(result);
9844 return 0;
9845 }
9846 Z_TRY_ADDREF_P(val);
9847 } ZEND_HASH_FOREACH_END();
9848
9849 continue;
9850 } else {
9851 zend_error_noreturn(E_COMPILE_ERROR, "Only arrays and Traversables can be unpacked, %s given", zend_zval_value_name(value));
9852 }
9853 }
9854
9855 Z_TRY_ADDREF_P(value);
9856
9857 key_ast = elem_ast->child[1];
9858 if (key_ast) {
9859 zval *key = zend_ast_get_zval(key_ast);
9860 switch (Z_TYPE_P(key)) {
9861 case IS_LONG:
9862 zend_hash_index_update(Z_ARRVAL_P(result), Z_LVAL_P(key), value);
9863 break;
9864 case IS_STRING:
9865 zend_symtable_update(Z_ARRVAL_P(result), Z_STR_P(key), value);
9866 break;
9867 case IS_DOUBLE: {
9868 zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
9869 /* Incompatible float will generate an error, leave this to run-time */
9870 if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
9871 zval_ptr_dtor_nogc(value);
9872 zval_ptr_dtor(result);
9873 return 0;
9874 }
9875 zend_hash_index_update(Z_ARRVAL_P(result), lval, value);
9876 break;
9877 }
9878 case IS_FALSE:
9879 zend_hash_index_update(Z_ARRVAL_P(result), 0, value);
9880 break;
9881 case IS_TRUE:
9882 zend_hash_index_update(Z_ARRVAL_P(result), 1, value);
9883 break;
9884 case IS_NULL:
9885 zend_hash_update(Z_ARRVAL_P(result), ZSTR_EMPTY_ALLOC(), value);
9886 break;
9887 default:
9888 zend_error_noreturn(E_COMPILE_ERROR, "Illegal offset type");
9889 break;
9890 }
9891 } else if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), value)) {
9892 zval_ptr_dtor_nogc(value);
9893 zval_ptr_dtor(result);
9894 return 0;
9895 }
9896 }
9897
9898 return 1;
9899 }
9900 /* }}} */
9901
zend_compile_binary_op(znode * result,zend_ast * ast)9902 static void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */
9903 {
9904 zend_ast *left_ast = ast->child[0];
9905 zend_ast *right_ast = ast->child[1];
9906 uint32_t opcode = ast->attr;
9907
9908 znode left_node, right_node;
9909
9910 zend_compile_expr(&left_node, left_ast);
9911 zend_compile_expr(&right_node, right_ast);
9912
9913 if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
9914 if (zend_try_ct_eval_binary_op(&result->u.constant, opcode,
9915 &left_node.u.constant, &right_node.u.constant)
9916 ) {
9917 result->op_type = IS_CONST;
9918 zval_ptr_dtor(&left_node.u.constant);
9919 zval_ptr_dtor(&right_node.u.constant);
9920 return;
9921 }
9922 }
9923
9924 do {
9925 if (opcode == ZEND_IS_EQUAL || opcode == ZEND_IS_NOT_EQUAL) {
9926 if (left_node.op_type == IS_CONST) {
9927 if (Z_TYPE(left_node.u.constant) == IS_FALSE) {
9928 opcode = (opcode == ZEND_IS_NOT_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
9929 zend_emit_op_tmp(result, opcode, &right_node, NULL);
9930 break;
9931 } else if (Z_TYPE(left_node.u.constant) == IS_TRUE) {
9932 opcode = (opcode == ZEND_IS_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
9933 zend_emit_op_tmp(result, opcode, &right_node, NULL);
9934 break;
9935 }
9936 } else if (right_node.op_type == IS_CONST) {
9937 if (Z_TYPE(right_node.u.constant) == IS_FALSE) {
9938 opcode = (opcode == ZEND_IS_NOT_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
9939 zend_emit_op_tmp(result, opcode, &left_node, NULL);
9940 break;
9941 } else if (Z_TYPE(right_node.u.constant) == IS_TRUE) {
9942 opcode = (opcode == ZEND_IS_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
9943 zend_emit_op_tmp(result, opcode, &left_node, NULL);
9944 break;
9945 }
9946 }
9947 } else if (opcode == ZEND_IS_IDENTICAL || opcode == ZEND_IS_NOT_IDENTICAL) {
9948 /* convert $x === null to is_null($x) (i.e. ZEND_TYPE_CHECK opcode). Do the same thing for false/true. (covers IS_NULL, IS_FALSE, and IS_TRUE) */
9949 if (left_node.op_type == IS_CONST) {
9950 if (Z_TYPE(left_node.u.constant) <= IS_TRUE && Z_TYPE(left_node.u.constant) >= IS_NULL) {
9951 zend_op *opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &right_node, NULL);
9952 opline->extended_value =
9953 (opcode == ZEND_IS_IDENTICAL) ?
9954 (1 << Z_TYPE(left_node.u.constant)) :
9955 (MAY_BE_ANY - (1 << Z_TYPE(left_node.u.constant)));
9956 return;
9957 }
9958 } else if (right_node.op_type == IS_CONST) {
9959 if (Z_TYPE(right_node.u.constant) <= IS_TRUE && Z_TYPE(right_node.u.constant) >= IS_NULL) {
9960 zend_op *opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &left_node, NULL);
9961 opline->extended_value =
9962 (opcode == ZEND_IS_IDENTICAL) ?
9963 (1 << Z_TYPE(right_node.u.constant)) :
9964 (MAY_BE_ANY - (1 << Z_TYPE(right_node.u.constant)));
9965 return;
9966 }
9967 }
9968 } else if (opcode == ZEND_CONCAT) {
9969 /* convert constant operands to strings at compile-time */
9970 if (left_node.op_type == IS_CONST) {
9971 if (Z_TYPE(left_node.u.constant) == IS_ARRAY) {
9972 zend_emit_op_tmp(&left_node, ZEND_CAST, &left_node, NULL)->extended_value = IS_STRING;
9973 } else {
9974 convert_to_string(&left_node.u.constant);
9975 }
9976 }
9977 if (right_node.op_type == IS_CONST) {
9978 if (Z_TYPE(right_node.u.constant) == IS_ARRAY) {
9979 zend_emit_op_tmp(&right_node, ZEND_CAST, &right_node, NULL)->extended_value = IS_STRING;
9980 } else {
9981 convert_to_string(&right_node.u.constant);
9982 }
9983 }
9984 if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
9985 opcode = ZEND_FAST_CONCAT;
9986 }
9987 }
9988 zend_emit_op_tmp(result, opcode, &left_node, &right_node);
9989 } while (0);
9990 }
9991 /* }}} */
9992
9993 /* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
9994 * evaluation order. */
zend_compile_greater(znode * result,zend_ast * ast)9995 static void zend_compile_greater(znode *result, zend_ast *ast) /* {{{ */
9996 {
9997 zend_ast *left_ast = ast->child[0];
9998 zend_ast *right_ast = ast->child[1];
9999 znode left_node, right_node;
10000
10001 ZEND_ASSERT(ast->kind == ZEND_AST_GREATER || ast->kind == ZEND_AST_GREATER_EQUAL);
10002
10003 zend_compile_expr(&left_node, left_ast);
10004 zend_compile_expr(&right_node, right_ast);
10005
10006 if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
10007 result->op_type = IS_CONST;
10008 zend_ct_eval_greater(&result->u.constant, ast->kind,
10009 &left_node.u.constant, &right_node.u.constant);
10010 zval_ptr_dtor(&left_node.u.constant);
10011 zval_ptr_dtor(&right_node.u.constant);
10012 return;
10013 }
10014
10015 zend_emit_op_tmp(result,
10016 ast->kind == ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL,
10017 &right_node, &left_node);
10018 }
10019 /* }}} */
10020
zend_compile_unary_op(znode * result,zend_ast * ast)10021 static void zend_compile_unary_op(znode *result, zend_ast *ast) /* {{{ */
10022 {
10023 zend_ast *expr_ast = ast->child[0];
10024 uint32_t opcode = ast->attr;
10025
10026 znode expr_node;
10027 zend_compile_expr(&expr_node, expr_ast);
10028
10029 if (expr_node.op_type == IS_CONST
10030 && zend_try_ct_eval_unary_op(&result->u.constant, opcode, &expr_node.u.constant)) {
10031 result->op_type = IS_CONST;
10032 zval_ptr_dtor(&expr_node.u.constant);
10033 return;
10034 }
10035
10036 zend_emit_op_tmp(result, opcode, &expr_node, NULL);
10037 }
10038 /* }}} */
10039
zend_compile_unary_pm(znode * result,zend_ast * ast)10040 static void zend_compile_unary_pm(znode *result, zend_ast *ast) /* {{{ */
10041 {
10042 zend_ast *expr_ast = ast->child[0];
10043 znode expr_node, right_node;
10044
10045 ZEND_ASSERT(ast->kind == ZEND_AST_UNARY_PLUS || ast->kind == ZEND_AST_UNARY_MINUS);
10046
10047 zend_compile_expr(&expr_node, expr_ast);
10048
10049 if (expr_node.op_type == IS_CONST
10050 && zend_try_ct_eval_unary_pm(&result->u.constant, ast->kind, &expr_node.u.constant)) {
10051 result->op_type = IS_CONST;
10052 zval_ptr_dtor(&expr_node.u.constant);
10053 return;
10054 }
10055
10056 right_node.op_type = IS_CONST;
10057 ZVAL_LONG(&right_node.u.constant, (ast->kind == ZEND_AST_UNARY_PLUS) ? 1 : -1);
10058 zend_emit_op_tmp(result, ZEND_MUL, &expr_node, &right_node);
10059 }
10060 /* }}} */
10061
zend_compile_short_circuiting(znode * result,zend_ast * ast)10062 static void zend_compile_short_circuiting(znode *result, zend_ast *ast) /* {{{ */
10063 {
10064 zend_ast *left_ast = ast->child[0];
10065 zend_ast *right_ast = ast->child[1];
10066
10067 znode left_node, right_node;
10068 zend_op *opline_jmpz, *opline_bool;
10069 uint32_t opnum_jmpz;
10070
10071 ZEND_ASSERT(ast->kind == ZEND_AST_AND || ast->kind == ZEND_AST_OR);
10072
10073 zend_compile_expr(&left_node, left_ast);
10074
10075 if (left_node.op_type == IS_CONST) {
10076 if ((ast->kind == ZEND_AST_AND && !zend_is_true(&left_node.u.constant))
10077 || (ast->kind == ZEND_AST_OR && zend_is_true(&left_node.u.constant))) {
10078 result->op_type = IS_CONST;
10079 ZVAL_BOOL(&result->u.constant, zend_is_true(&left_node.u.constant));
10080 } else {
10081 zend_compile_expr(&right_node, right_ast);
10082
10083 if (right_node.op_type == IS_CONST) {
10084 result->op_type = IS_CONST;
10085 ZVAL_BOOL(&result->u.constant, zend_is_true(&right_node.u.constant));
10086
10087 zval_ptr_dtor(&right_node.u.constant);
10088 } else {
10089 zend_emit_op_tmp(result, ZEND_BOOL, &right_node, NULL);
10090 }
10091 }
10092
10093 zval_ptr_dtor(&left_node.u.constant);
10094 return;
10095 }
10096
10097 opnum_jmpz = get_next_op_number();
10098 opline_jmpz = zend_emit_op(NULL, ast->kind == ZEND_AST_AND ? ZEND_JMPZ_EX : ZEND_JMPNZ_EX,
10099 &left_node, NULL);
10100
10101 if (left_node.op_type == IS_TMP_VAR) {
10102 SET_NODE(opline_jmpz->result, &left_node);
10103 GET_NODE(result, opline_jmpz->result);
10104 } else {
10105 zend_make_tmp_result(result, opline_jmpz);
10106 }
10107
10108 zend_compile_expr(&right_node, right_ast);
10109
10110 opline_bool = zend_emit_op(NULL, ZEND_BOOL, &right_node, NULL);
10111 SET_NODE(opline_bool->result, result);
10112
10113 zend_update_jump_target_to_next(opnum_jmpz);
10114 }
10115 /* }}} */
10116
zend_compile_post_incdec(znode * result,zend_ast * ast)10117 static void zend_compile_post_incdec(znode *result, zend_ast *ast) /* {{{ */
10118 {
10119 zend_ast *var_ast = ast->child[0];
10120 ZEND_ASSERT(ast->kind == ZEND_AST_POST_INC || ast->kind == ZEND_AST_POST_DEC);
10121
10122 zend_ensure_writable_variable(var_ast);
10123
10124 if (var_ast->kind == ZEND_AST_PROP || var_ast->kind == ZEND_AST_NULLSAFE_PROP) {
10125 zend_op *opline = zend_compile_prop(NULL, var_ast, BP_VAR_RW, 0);
10126 opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ;
10127 zend_make_tmp_result(result, opline);
10128 } else if (var_ast->kind == ZEND_AST_STATIC_PROP) {
10129 zend_op *opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_RW, 0, 0);
10130 opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_STATIC_PROP : ZEND_POST_DEC_STATIC_PROP;
10131 zend_make_tmp_result(result, opline);
10132 } else {
10133 znode var_node;
10134 zend_op *opline = zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
10135 if (opline && opline->opcode == ZEND_FETCH_DIM_RW) {
10136 opline->extended_value = ZEND_FETCH_DIM_INCDEC;
10137 }
10138 zend_emit_op_tmp(result, ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC,
10139 &var_node, NULL);
10140 }
10141 }
10142 /* }}} */
10143
zend_compile_pre_incdec(znode * result,zend_ast * ast)10144 static void zend_compile_pre_incdec(znode *result, zend_ast *ast) /* {{{ */
10145 {
10146 zend_ast *var_ast = ast->child[0];
10147 ZEND_ASSERT(ast->kind == ZEND_AST_PRE_INC || ast->kind == ZEND_AST_PRE_DEC);
10148
10149 zend_ensure_writable_variable(var_ast);
10150
10151 if (var_ast->kind == ZEND_AST_PROP || var_ast->kind == ZEND_AST_NULLSAFE_PROP) {
10152 zend_op *opline = zend_compile_prop(result, var_ast, BP_VAR_RW, 0);
10153 opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ;
10154 opline->result_type = IS_TMP_VAR;
10155 result->op_type = IS_TMP_VAR;
10156 } else if (var_ast->kind == ZEND_AST_STATIC_PROP) {
10157 zend_op *opline = zend_compile_static_prop(result, var_ast, BP_VAR_RW, 0, 0);
10158 opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_STATIC_PROP : ZEND_PRE_DEC_STATIC_PROP;
10159 opline->result_type = IS_TMP_VAR;
10160 result->op_type = IS_TMP_VAR;
10161 } else {
10162 znode var_node;
10163 zend_op *opline = zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
10164 if (opline && opline->opcode == ZEND_FETCH_DIM_RW) {
10165 opline->extended_value = ZEND_FETCH_DIM_INCDEC;
10166 }
10167 zend_emit_op_tmp(result, ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC,
10168 &var_node, NULL);
10169 }
10170 }
10171 /* }}} */
10172
zend_compile_cast(znode * result,zend_ast * ast)10173 static void zend_compile_cast(znode *result, zend_ast *ast) /* {{{ */
10174 {
10175 zend_ast *expr_ast = ast->child[0];
10176 znode expr_node;
10177 zend_op *opline;
10178
10179 zend_compile_expr(&expr_node, expr_ast);
10180
10181 if (ast->attr == _IS_BOOL) {
10182 opline = zend_emit_op_tmp(result, ZEND_BOOL, &expr_node, NULL);
10183 } else if (ast->attr == IS_NULL) {
10184 zend_error(E_COMPILE_ERROR, "The (unset) cast is no longer supported");
10185 } else {
10186 opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL);
10187 opline->extended_value = ast->attr;
10188 }
10189 }
10190 /* }}} */
10191
zend_compile_shorthand_conditional(znode * result,zend_ast * ast)10192 static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast) /* {{{ */
10193 {
10194 zend_ast *cond_ast = ast->child[0];
10195 zend_ast *false_ast = ast->child[2];
10196
10197 znode cond_node, false_node;
10198 zend_op *opline_qm_assign;
10199 uint32_t opnum_jmp_set;
10200
10201 ZEND_ASSERT(ast->child[1] == NULL);
10202
10203 zend_compile_expr(&cond_node, cond_ast);
10204
10205 opnum_jmp_set = get_next_op_number();
10206 zend_emit_op_tmp(result, ZEND_JMP_SET, &cond_node, NULL);
10207
10208 zend_compile_expr(&false_node, false_ast);
10209
10210 opline_qm_assign = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &false_node, NULL);
10211 SET_NODE(opline_qm_assign->result, result);
10212
10213 zend_update_jump_target_to_next(opnum_jmp_set);
10214 }
10215 /* }}} */
10216
zend_compile_conditional(znode * result,zend_ast * ast)10217 static void zend_compile_conditional(znode *result, zend_ast *ast) /* {{{ */
10218 {
10219 zend_ast *cond_ast = ast->child[0];
10220 zend_ast *true_ast = ast->child[1];
10221 zend_ast *false_ast = ast->child[2];
10222
10223 znode cond_node, true_node, false_node;
10224 zend_op *opline_qm_assign2;
10225 uint32_t opnum_jmpz, opnum_jmp;
10226
10227 if (cond_ast->kind == ZEND_AST_CONDITIONAL
10228 && cond_ast->attr != ZEND_PARENTHESIZED_CONDITIONAL) {
10229 if (cond_ast->child[1]) {
10230 if (true_ast) {
10231 zend_error(E_COMPILE_ERROR,
10232 "Unparenthesized `a ? b : c ? d : e` is not supported. "
10233 "Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`");
10234 } else {
10235 zend_error(E_COMPILE_ERROR,
10236 "Unparenthesized `a ? b : c ?: d` is not supported. "
10237 "Use either `(a ? b : c) ?: d` or `a ? b : (c ?: d)`");
10238 }
10239 } else {
10240 if (true_ast) {
10241 zend_error(E_COMPILE_ERROR,
10242 "Unparenthesized `a ?: b ? c : d` is not supported. "
10243 "Use either `(a ?: b) ? c : d` or `a ?: (b ? c : d)`");
10244 } else {
10245 /* This case is harmless: (a ?: b) ?: c always produces the same result
10246 * as a ?: (b ?: c). */
10247 }
10248 }
10249 }
10250
10251 if (!true_ast) {
10252 zend_compile_shorthand_conditional(result, ast);
10253 return;
10254 }
10255
10256 zend_compile_expr(&cond_node, cond_ast);
10257
10258 opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0);
10259
10260 zend_compile_expr(&true_node, true_ast);
10261
10262 zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &true_node, NULL);
10263
10264 opnum_jmp = zend_emit_jump(0);
10265
10266 zend_update_jump_target_to_next(opnum_jmpz);
10267
10268 zend_compile_expr(&false_node, false_ast);
10269
10270 opline_qm_assign2 = zend_emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL);
10271 SET_NODE(opline_qm_assign2->result, result);
10272
10273 zend_update_jump_target_to_next(opnum_jmp);
10274 }
10275 /* }}} */
10276
zend_compile_coalesce(znode * result,zend_ast * ast)10277 static void zend_compile_coalesce(znode *result, zend_ast *ast) /* {{{ */
10278 {
10279 zend_ast *expr_ast = ast->child[0];
10280 zend_ast *default_ast = ast->child[1];
10281
10282 znode expr_node, default_node;
10283 zend_op *opline;
10284 uint32_t opnum;
10285
10286 zend_compile_var(&expr_node, expr_ast, BP_VAR_IS, 0);
10287
10288 opnum = get_next_op_number();
10289 zend_emit_op_tmp(result, ZEND_COALESCE, &expr_node, NULL);
10290
10291 zend_compile_expr(&default_node, default_ast);
10292
10293 opline = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &default_node, NULL);
10294 SET_NODE(opline->result, result);
10295
10296 opline = &CG(active_op_array)->opcodes[opnum];
10297 opline->op2.opline_num = get_next_op_number();
10298 }
10299 /* }}} */
10300
znode_dtor(zval * zv)10301 static void znode_dtor(zval *zv) {
10302 znode *node = Z_PTR_P(zv);
10303 if (node->op_type == IS_CONST) {
10304 zval_ptr_dtor_nogc(&node->u.constant);
10305 }
10306 efree(node);
10307 }
10308
zend_compile_assign_coalesce(znode * result,zend_ast * ast)10309 static void zend_compile_assign_coalesce(znode *result, zend_ast *ast) /* {{{ */
10310 {
10311 zend_ast *var_ast = ast->child[0];
10312 zend_ast *default_ast = ast->child[1];
10313
10314 znode var_node_is, var_node_w, default_node, assign_node, *node;
10315 zend_op *opline;
10316 uint32_t coalesce_opnum;
10317 bool need_frees = 0;
10318
10319 /* Remember expressions compiled during the initial BP_VAR_IS lookup,
10320 * to avoid double-evaluation when we compile again with BP_VAR_W. */
10321 HashTable *orig_memoized_exprs = CG(memoized_exprs);
10322 const zend_memoize_mode orig_memoize_mode = CG(memoize_mode);
10323
10324 zend_ensure_writable_variable(var_ast);
10325 if (is_this_fetch(var_ast)) {
10326 zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
10327 }
10328
10329 ALLOC_HASHTABLE(CG(memoized_exprs));
10330 zend_hash_init(CG(memoized_exprs), 0, NULL, znode_dtor, 0);
10331
10332 CG(memoize_mode) = ZEND_MEMOIZE_COMPILE;
10333 zend_compile_var(&var_node_is, var_ast, BP_VAR_IS, 0);
10334
10335 coalesce_opnum = get_next_op_number();
10336 zend_emit_op_tmp(result, ZEND_COALESCE, &var_node_is, NULL);
10337
10338 CG(memoize_mode) = ZEND_MEMOIZE_NONE;
10339 if (var_ast->kind == ZEND_AST_DIM) {
10340 zend_compile_expr_with_potential_assign_to_self(&default_node, default_ast, var_ast);
10341 } else {
10342 zend_compile_expr(&default_node, default_ast);
10343 }
10344
10345 CG(memoize_mode) = ZEND_MEMOIZE_FETCH;
10346 zend_compile_var(&var_node_w, var_ast, BP_VAR_W, 0);
10347
10348 /* Reproduce some of the zend_compile_assign() opcode fixup logic here. */
10349 opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
10350 /* Treat $GLOBALS['x'] assignment like assignment to variable. */
10351 zend_ast_kind kind = is_global_var_fetch(var_ast) ? ZEND_AST_VAR : var_ast->kind;
10352 switch (kind) {
10353 case ZEND_AST_VAR:
10354 zend_emit_op_tmp(&assign_node, ZEND_ASSIGN, &var_node_w, &default_node);
10355 break;
10356 case ZEND_AST_STATIC_PROP:
10357 opline->opcode = ZEND_ASSIGN_STATIC_PROP;
10358 opline->result_type = IS_TMP_VAR;
10359 var_node_w.op_type = IS_TMP_VAR;
10360 zend_emit_op_data(&default_node);
10361 assign_node = var_node_w;
10362 break;
10363 case ZEND_AST_DIM:
10364 opline->opcode = ZEND_ASSIGN_DIM;
10365 opline->result_type = IS_TMP_VAR;
10366 var_node_w.op_type = IS_TMP_VAR;
10367 zend_emit_op_data(&default_node);
10368 assign_node = var_node_w;
10369 break;
10370 case ZEND_AST_PROP:
10371 case ZEND_AST_NULLSAFE_PROP:
10372 opline->opcode = ZEND_ASSIGN_OBJ;
10373 opline->result_type = IS_TMP_VAR;
10374 var_node_w.op_type = IS_TMP_VAR;
10375 zend_emit_op_data(&default_node);
10376 assign_node = var_node_w;
10377 break;
10378 EMPTY_SWITCH_DEFAULT_CASE();
10379 }
10380
10381 opline = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &assign_node, NULL);
10382 SET_NODE(opline->result, result);
10383
10384 ZEND_HASH_FOREACH_PTR(CG(memoized_exprs), node) {
10385 if (node->op_type == IS_TMP_VAR || node->op_type == IS_VAR) {
10386 need_frees = 1;
10387 break;
10388 }
10389 } ZEND_HASH_FOREACH_END();
10390
10391 /* Free DUPed expressions if there are any */
10392 if (need_frees) {
10393 uint32_t jump_opnum = zend_emit_jump(0);
10394 zend_update_jump_target_to_next(coalesce_opnum);
10395 ZEND_HASH_FOREACH_PTR(CG(memoized_exprs), node) {
10396 if (node->op_type == IS_TMP_VAR || node->op_type == IS_VAR) {
10397 zend_emit_op(NULL, ZEND_FREE, node, NULL);
10398 }
10399 } ZEND_HASH_FOREACH_END();
10400 zend_update_jump_target_to_next(jump_opnum);
10401 } else {
10402 zend_update_jump_target_to_next(coalesce_opnum);
10403 }
10404
10405 zend_hash_destroy(CG(memoized_exprs));
10406 FREE_HASHTABLE(CG(memoized_exprs));
10407 CG(memoized_exprs) = orig_memoized_exprs;
10408 CG(memoize_mode) = orig_memoize_mode;
10409 }
10410 /* }}} */
10411
zend_compile_print(znode * result,zend_ast * ast)10412 static void zend_compile_print(znode *result, zend_ast *ast) /* {{{ */
10413 {
10414 zend_op *opline;
10415 zend_ast *expr_ast = ast->child[0];
10416
10417 znode expr_node;
10418 zend_compile_expr(&expr_node, expr_ast);
10419
10420 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL);
10421 opline->extended_value = 1;
10422
10423 result->op_type = IS_CONST;
10424 ZVAL_LONG(&result->u.constant, 1);
10425 }
10426 /* }}} */
10427
zend_compile_yield(znode * result,zend_ast * ast)10428 static void zend_compile_yield(znode *result, zend_ast *ast) /* {{{ */
10429 {
10430 zend_ast *value_ast = ast->child[0];
10431 zend_ast *key_ast = ast->child[1];
10432
10433 znode value_node, key_node;
10434 znode *value_node_ptr = NULL, *key_node_ptr = NULL;
10435 zend_op *opline;
10436 bool returns_by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
10437
10438 zend_mark_function_as_generator();
10439
10440 if (key_ast) {
10441 zend_compile_expr(&key_node, key_ast);
10442 key_node_ptr = &key_node;
10443 }
10444
10445 if (value_ast) {
10446 if (returns_by_ref && zend_is_variable(value_ast)) {
10447 zend_assert_not_short_circuited(value_ast);
10448 zend_compile_var(&value_node, value_ast, BP_VAR_W, 1);
10449 } else {
10450 zend_compile_expr(&value_node, value_ast);
10451 }
10452 value_node_ptr = &value_node;
10453 }
10454
10455 opline = zend_emit_op(result, ZEND_YIELD, value_node_ptr, key_node_ptr);
10456
10457 if (value_ast && returns_by_ref && zend_is_call(value_ast)) {
10458 opline->extended_value = ZEND_RETURNS_FUNCTION;
10459 }
10460 }
10461 /* }}} */
10462
zend_compile_yield_from(znode * result,zend_ast * ast)10463 static void zend_compile_yield_from(znode *result, zend_ast *ast) /* {{{ */
10464 {
10465 zend_ast *expr_ast = ast->child[0];
10466 znode expr_node;
10467
10468 zend_mark_function_as_generator();
10469
10470 if (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
10471 zend_error_noreturn(E_COMPILE_ERROR,
10472 "Cannot use \"yield from\" inside a by-reference generator");
10473 }
10474
10475 zend_compile_expr(&expr_node, expr_ast);
10476 zend_emit_op_tmp(result, ZEND_YIELD_FROM, &expr_node, NULL);
10477 }
10478 /* }}} */
10479
zend_compile_instanceof(znode * result,zend_ast * ast)10480 static void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */
10481 {
10482 zend_ast *obj_ast = ast->child[0];
10483 zend_ast *class_ast = ast->child[1];
10484
10485 znode obj_node, class_node;
10486 zend_op *opline;
10487
10488 zend_compile_expr(&obj_node, obj_ast);
10489 if (obj_node.op_type == IS_CONST) {
10490 zend_do_free(&obj_node);
10491 result->op_type = IS_CONST;
10492 ZVAL_FALSE(&result->u.constant);
10493 return;
10494 }
10495
10496 zend_compile_class_ref(&class_node, class_ast,
10497 ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_EXCEPTION | ZEND_FETCH_CLASS_SILENT);
10498
10499 opline = zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, NULL);
10500
10501 if (class_node.op_type == IS_CONST) {
10502 opline->op2_type = IS_CONST;
10503 opline->op2.constant = zend_add_class_name_literal(
10504 Z_STR(class_node.u.constant));
10505 opline->extended_value = zend_alloc_cache_slot();
10506 } else {
10507 SET_NODE(opline->op2, &class_node);
10508 }
10509 }
10510 /* }}} */
10511
zend_compile_include_or_eval(znode * result,zend_ast * ast)10512 static void zend_compile_include_or_eval(znode *result, zend_ast *ast) /* {{{ */
10513 {
10514 zend_ast *expr_ast = ast->child[0];
10515 znode expr_node;
10516 zend_op *opline;
10517
10518 zend_do_extended_fcall_begin();
10519 zend_compile_expr(&expr_node, expr_ast);
10520
10521 opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL);
10522 opline->extended_value = ast->attr;
10523
10524 zend_do_extended_fcall_end();
10525 }
10526 /* }}} */
10527
zend_compile_isset_or_empty(znode * result,zend_ast * ast)10528 static void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
10529 {
10530 zend_ast *var_ast = ast->child[0];
10531
10532 znode var_node;
10533 zend_op *opline = NULL;
10534
10535 ZEND_ASSERT(ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY);
10536
10537 if (!zend_is_variable(var_ast)) {
10538 if (ast->kind == ZEND_AST_EMPTY) {
10539 /* empty(expr) can be transformed to !expr */
10540 zend_ast *not_ast = zend_ast_create_ex(ZEND_AST_UNARY_OP, ZEND_BOOL_NOT, var_ast);
10541 zend_compile_expr(result, not_ast);
10542 return;
10543 } else {
10544 zend_error_noreturn(E_COMPILE_ERROR,
10545 "Cannot use isset() on the result of an expression "
10546 "(you can use \"null !== expression\" instead)");
10547 }
10548 }
10549
10550 if (is_globals_fetch(var_ast)) {
10551 result->op_type = IS_CONST;
10552 ZVAL_BOOL(&result->u.constant, ast->kind == ZEND_AST_ISSET);
10553 return;
10554 }
10555
10556 if (is_global_var_fetch(var_ast)) {
10557 if (!var_ast->child[1]) {
10558 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
10559 }
10560
10561 zend_compile_expr(&var_node, var_ast->child[1]);
10562 if (var_node.op_type == IS_CONST) {
10563 convert_to_string(&var_node.u.constant);
10564 }
10565
10566 opline = zend_emit_op_tmp(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL);
10567 opline->extended_value =
10568 ZEND_FETCH_GLOBAL | (ast->kind == ZEND_AST_EMPTY ? ZEND_ISEMPTY : 0);
10569 return;
10570 }
10571
10572 zend_short_circuiting_mark_inner(var_ast);
10573 switch (var_ast->kind) {
10574 case ZEND_AST_VAR:
10575 if (is_this_fetch(var_ast)) {
10576 opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
10577 CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
10578 } else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
10579 opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_CV, &var_node, NULL);
10580 } else {
10581 opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS, 0);
10582 opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
10583 }
10584 break;
10585 case ZEND_AST_DIM:
10586 opline = zend_compile_dim(result, var_ast, BP_VAR_IS, /* by_ref */ false);
10587 opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
10588 break;
10589 case ZEND_AST_PROP:
10590 case ZEND_AST_NULLSAFE_PROP:
10591 opline = zend_compile_prop(result, var_ast, BP_VAR_IS, 0);
10592 opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ;
10593 break;
10594 case ZEND_AST_STATIC_PROP:
10595 opline = zend_compile_static_prop(result, var_ast, BP_VAR_IS, 0, 0);
10596 opline->opcode = ZEND_ISSET_ISEMPTY_STATIC_PROP;
10597 break;
10598 EMPTY_SWITCH_DEFAULT_CASE()
10599 }
10600
10601 result->op_type = opline->result_type = IS_TMP_VAR;
10602 if (!(ast->kind == ZEND_AST_ISSET)) {
10603 opline->extended_value |= ZEND_ISEMPTY;
10604 }
10605 }
10606 /* }}} */
10607
zend_compile_silence(znode * result,zend_ast * ast)10608 static void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
10609 {
10610 zend_ast *expr_ast = ast->child[0];
10611 znode silence_node;
10612
10613 zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
10614
10615 if (expr_ast->kind == ZEND_AST_VAR) {
10616 /* For @$var we need to force a FETCH instruction, otherwise the CV access will
10617 * happen outside the silenced section. */
10618 zend_compile_simple_var_no_cv(result, expr_ast, BP_VAR_R, 0 );
10619 } else {
10620 zend_compile_expr(result, expr_ast);
10621 }
10622
10623 zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
10624 }
10625 /* }}} */
10626
zend_compile_shell_exec(znode * result,zend_ast * ast)10627 static void zend_compile_shell_exec(znode *result, zend_ast *ast) /* {{{ */
10628 {
10629 zend_ast *expr_ast = ast->child[0];
10630
10631 zval fn_name;
10632 zend_ast *name_ast, *args_ast, *call_ast;
10633
10634 ZVAL_STRING(&fn_name, "shell_exec");
10635 name_ast = zend_ast_create_zval(&fn_name);
10636 args_ast = zend_ast_create_list(1, ZEND_AST_ARG_LIST, expr_ast);
10637 call_ast = zend_ast_create(ZEND_AST_CALL, name_ast, args_ast);
10638
10639 zend_compile_expr(result, call_ast);
10640
10641 zval_ptr_dtor(&fn_name);
10642 }
10643 /* }}} */
10644
zend_compile_array(znode * result,zend_ast * ast)10645 static void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */
10646 {
10647 zend_ast_list *list = zend_ast_get_list(ast);
10648 zend_op *opline;
10649 uint32_t i, opnum_init = -1;
10650 bool packed = 1;
10651
10652 if (zend_try_ct_eval_array(&result->u.constant, ast)) {
10653 result->op_type = IS_CONST;
10654 return;
10655 }
10656
10657 /* Empty arrays are handled at compile-time */
10658 ZEND_ASSERT(list->children > 0);
10659
10660 for (i = 0; i < list->children; ++i) {
10661 zend_ast *elem_ast = list->child[i];
10662 zend_ast *value_ast, *key_ast;
10663 bool by_ref;
10664 znode value_node, key_node, *key_node_ptr = NULL;
10665
10666 if (elem_ast == NULL) {
10667 zend_error(E_COMPILE_ERROR, "Cannot use empty array elements in arrays");
10668 }
10669
10670 value_ast = elem_ast->child[0];
10671
10672 if (elem_ast->kind == ZEND_AST_UNPACK) {
10673 zend_compile_expr(&value_node, value_ast);
10674 if (i == 0) {
10675 opnum_init = get_next_op_number();
10676 opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, NULL, NULL);
10677 }
10678 opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_UNPACK, &value_node, NULL);
10679 SET_NODE(opline->result, result);
10680 continue;
10681 }
10682
10683 key_ast = elem_ast->child[1];
10684 by_ref = elem_ast->attr;
10685
10686 if (key_ast) {
10687 zend_compile_expr(&key_node, key_ast);
10688 zend_handle_numeric_op(&key_node);
10689 key_node_ptr = &key_node;
10690 }
10691
10692 if (by_ref) {
10693 zend_ensure_writable_variable(value_ast);
10694 zend_compile_var(&value_node, value_ast, BP_VAR_W, 1);
10695 } else {
10696 zend_compile_expr(&value_node, value_ast);
10697 }
10698
10699 if (i == 0) {
10700 opnum_init = get_next_op_number();
10701 opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr);
10702 opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT;
10703 } else {
10704 opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT,
10705 &value_node, key_node_ptr);
10706 SET_NODE(opline->result, result);
10707 }
10708 opline->extended_value |= by_ref;
10709
10710 if (key_ast && key_node.op_type == IS_CONST && Z_TYPE(key_node.u.constant) == IS_STRING) {
10711 packed = 0;
10712 }
10713 }
10714
10715 /* Add a flag to INIT_ARRAY if we know this array cannot be packed */
10716 if (!packed) {
10717 ZEND_ASSERT(opnum_init != (uint32_t)-1);
10718 opline = &CG(active_op_array)->opcodes[opnum_init];
10719 opline->extended_value |= ZEND_ARRAY_NOT_PACKED;
10720 }
10721 }
10722 /* }}} */
10723
zend_compile_const(znode * result,zend_ast * ast)10724 static void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */
10725 {
10726 zend_ast *name_ast = ast->child[0];
10727
10728 zend_op *opline;
10729
10730 bool is_fully_qualified;
10731 zend_string *orig_name = zend_ast_get_str(name_ast);
10732 zend_string *resolved_name = zend_resolve_const_name(orig_name, name_ast->attr, &is_fully_qualified);
10733
10734 if (zend_string_equals_literal(resolved_name, "__COMPILER_HALT_OFFSET__") || (name_ast->attr != ZEND_NAME_RELATIVE && zend_string_equals_literal(orig_name, "__COMPILER_HALT_OFFSET__"))) {
10735 zend_ast *last = CG(ast);
10736
10737 while (last && last->kind == ZEND_AST_STMT_LIST) {
10738 zend_ast_list *list = zend_ast_get_list(last);
10739 if (list->children == 0) {
10740 break;
10741 }
10742 last = list->child[list->children-1];
10743 }
10744 if (last && last->kind == ZEND_AST_HALT_COMPILER) {
10745 result->op_type = IS_CONST;
10746 ZVAL_LONG(&result->u.constant, Z_LVAL_P(zend_ast_get_zval(last->child[0])));
10747 zend_string_release_ex(resolved_name, 0);
10748 return;
10749 }
10750 }
10751
10752 if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified)) {
10753 result->op_type = IS_CONST;
10754 zend_string_release_ex(resolved_name, 0);
10755 return;
10756 }
10757
10758 opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL);
10759 opline->op2_type = IS_CONST;
10760
10761 if (is_fully_qualified || !FC(current_namespace)) {
10762 opline->op1.num = 0;
10763 opline->op2.constant = zend_add_const_name_literal(
10764 resolved_name, 0);
10765 } else {
10766 opline->op1.num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE;
10767 opline->op2.constant = zend_add_const_name_literal(
10768 resolved_name, 1);
10769 }
10770 opline->extended_value = zend_alloc_cache_slot();
10771 }
10772 /* }}} */
10773
zend_compile_class_const(znode * result,zend_ast * ast)10774 static void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
10775 {
10776 zend_ast *class_ast;
10777 zend_ast *const_ast;
10778 znode class_node, const_node;
10779 zend_op *opline;
10780
10781 zend_eval_const_expr(&ast->child[0]);
10782 zend_eval_const_expr(&ast->child[1]);
10783
10784 class_ast = ast->child[0];
10785 const_ast = ast->child[1];
10786
10787 if (class_ast->kind == ZEND_AST_ZVAL && const_ast->kind == ZEND_AST_ZVAL) {
10788 zval *const_zv = zend_ast_get_zval(const_ast);
10789 if (Z_TYPE_P(const_zv) == IS_STRING) {
10790 zend_string *const_str = Z_STR_P(const_zv);
10791 zend_string *resolved_name = zend_resolve_class_name_ast(class_ast);
10792 if (zend_try_ct_eval_class_const(&result->u.constant, resolved_name, const_str)) {
10793 result->op_type = IS_CONST;
10794 zend_string_release_ex(resolved_name, 0);
10795 return;
10796 }
10797 zend_string_release_ex(resolved_name, 0);
10798 }
10799 }
10800
10801 zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
10802
10803 zend_compile_expr(&const_node, const_ast);
10804
10805 opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_CONSTANT, NULL, &const_node);
10806
10807 zend_set_class_name_op1(opline, &class_node);
10808
10809 if (opline->op1_type == IS_CONST || opline->op2_type == IS_CONST) {
10810 opline->extended_value = zend_alloc_cache_slots(2);
10811 }
10812 }
10813 /* }}} */
10814
zend_compile_class_name(znode * result,zend_ast * ast)10815 static void zend_compile_class_name(znode *result, zend_ast *ast) /* {{{ */
10816 {
10817 zend_ast *class_ast = ast->child[0];
10818
10819 if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast)) {
10820 result->op_type = IS_CONST;
10821 return;
10822 }
10823
10824 if (class_ast->kind == ZEND_AST_ZVAL) {
10825 zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
10826 opline->op1.num = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
10827 } else {
10828 znode expr_node;
10829 zend_compile_expr(&expr_node, class_ast);
10830 if (expr_node.op_type == IS_CONST) {
10831 /* Unlikely case that happen if class_ast is constant folded.
10832 * Handle it here, to avoid needing a CONST specialization in the VM. */
10833 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"::class\" on %s",
10834 zend_zval_value_name(&expr_node.u.constant));
10835 }
10836
10837 zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, &expr_node, NULL);
10838 }
10839 }
10840 /* }}} */
10841
zend_compile_rope_add_ex(zend_op * opline,znode * result,uint32_t num,znode * elem_node)10842 static zend_op *zend_compile_rope_add_ex(zend_op *opline, znode *result, uint32_t num, znode *elem_node) /* {{{ */
10843 {
10844 if (num == 0) {
10845 result->op_type = IS_TMP_VAR;
10846 result->u.op.var = -1;
10847 opline->opcode = ZEND_ROPE_INIT;
10848 } else {
10849 opline->opcode = ZEND_ROPE_ADD;
10850 SET_NODE(opline->op1, result);
10851 }
10852 SET_NODE(opline->op2, elem_node);
10853 SET_NODE(opline->result, result);
10854 opline->extended_value = num;
10855 return opline;
10856 }
10857 /* }}} */
10858
zend_compile_rope_add(znode * result,uint32_t num,znode * elem_node)10859 static zend_op *zend_compile_rope_add(znode *result, uint32_t num, znode *elem_node) /* {{{ */
10860 {
10861 zend_op *opline = get_next_op();
10862
10863 if (num == 0) {
10864 result->op_type = IS_TMP_VAR;
10865 result->u.op.var = -1;
10866 opline->opcode = ZEND_ROPE_INIT;
10867 } else {
10868 opline->opcode = ZEND_ROPE_ADD;
10869 SET_NODE(opline->op1, result);
10870 }
10871 SET_NODE(opline->op2, elem_node);
10872 SET_NODE(opline->result, result);
10873 opline->extended_value = num;
10874 return opline;
10875 }
10876 /* }}} */
10877
zend_compile_rope_finalize(znode * result,uint32_t rope_elements,zend_op * init_opline,zend_op * opline)10878 static void zend_compile_rope_finalize(znode *result, uint32_t rope_elements, zend_op *init_opline, zend_op *opline)
10879 {
10880 if (rope_elements == 1) {
10881 if (opline->op2_type == IS_CONST) {
10882 GET_NODE(result, opline->op2);
10883 ZVAL_UNDEF(CT_CONSTANT(opline->op2));
10884 SET_UNUSED(opline->op2);
10885 MAKE_NOP(opline);
10886 } else {
10887 opline->opcode = ZEND_CAST;
10888 opline->extended_value = IS_STRING;
10889 opline->op1_type = opline->op2_type;
10890 opline->op1 = opline->op2;
10891 SET_UNUSED(opline->op2);
10892 zend_make_tmp_result(result, opline);
10893 }
10894 } else if (rope_elements == 2) {
10895 opline->opcode = ZEND_FAST_CONCAT;
10896 opline->extended_value = 0;
10897 opline->op1_type = init_opline->op2_type;
10898 opline->op1 = init_opline->op2;
10899 zend_make_tmp_result(result, opline);
10900 MAKE_NOP(init_opline);
10901 } else {
10902 uint32_t var;
10903
10904 init_opline->extended_value = rope_elements;
10905 opline->opcode = ZEND_ROPE_END;
10906 zend_make_tmp_result(result, opline);
10907 var = opline->op1.var = get_temporary_variable();
10908
10909 /* Allocates the necessary number of zval slots to keep the rope */
10910 uint32_t i = ((rope_elements * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
10911 while (i > 1) {
10912 get_temporary_variable();
10913 i--;
10914 }
10915
10916 /* Update all the previous opcodes to use the same variable */
10917 while (opline != init_opline) {
10918 opline--;
10919 if (opline->opcode == ZEND_ROPE_ADD &&
10920 opline->result.var == (uint32_t)-1) {
10921 opline->op1.var = var;
10922 opline->result.var = var;
10923 } else if (opline->opcode == ZEND_ROPE_INIT &&
10924 opline->result.var == (uint32_t)-1) {
10925 opline->result.var = var;
10926 }
10927 }
10928 }
10929 }
10930
zend_compile_encaps_list(znode * result,zend_ast * ast)10931 static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
10932 {
10933 uint32_t i, j;
10934 uint32_t rope_init_lineno = -1;
10935 zend_op *opline = NULL, *init_opline;
10936 znode elem_node, last_const_node;
10937 zend_ast_list *list = zend_ast_get_list(ast);
10938 uint32_t reserved_op_number = -1;
10939
10940 ZEND_ASSERT(list->children > 0);
10941
10942 j = 0;
10943 last_const_node.op_type = IS_UNUSED;
10944 for (i = 0; i < list->children; i++) {
10945 zend_ast *encaps_var = list->child[i];
10946
10947 if (encaps_var->attr & (ZEND_ENCAPS_VAR_DOLLAR_CURLY|ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR)) {
10948 if ((encaps_var->kind == ZEND_AST_VAR || encaps_var->kind == ZEND_AST_DIM) && (encaps_var->attr & ZEND_ENCAPS_VAR_DOLLAR_CURLY)) {
10949 zend_error(E_DEPRECATED, "Using ${var} in strings is deprecated, use {$var} instead");
10950 } else if (encaps_var->kind == ZEND_AST_VAR && (encaps_var->attr & ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR)) {
10951 zend_error(E_DEPRECATED, "Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead");
10952 }
10953 }
10954
10955 zend_compile_expr(&elem_node, encaps_var);
10956
10957 if (elem_node.op_type == IS_CONST) {
10958 convert_to_string(&elem_node.u.constant);
10959
10960 if (Z_STRLEN(elem_node.u.constant) == 0) {
10961 zval_ptr_dtor(&elem_node.u.constant);
10962 } else if (last_const_node.op_type == IS_CONST) {
10963 concat_function(&last_const_node.u.constant, &last_const_node.u.constant, &elem_node.u.constant);
10964 zval_ptr_dtor(&elem_node.u.constant);
10965 } else {
10966 last_const_node.op_type = IS_CONST;
10967 ZVAL_COPY_VALUE(&last_const_node.u.constant, &elem_node.u.constant);
10968 /* Reserve place for ZEND_ROPE_ADD instruction */
10969 reserved_op_number = get_next_op_number();
10970 opline = get_next_op();
10971 opline->opcode = ZEND_NOP;
10972 }
10973 continue;
10974 } else {
10975 if (j == 0) {
10976 if (last_const_node.op_type == IS_CONST) {
10977 rope_init_lineno = reserved_op_number;
10978 } else {
10979 rope_init_lineno = get_next_op_number();
10980 }
10981 }
10982 if (last_const_node.op_type == IS_CONST) {
10983 opline = &CG(active_op_array)->opcodes[reserved_op_number];
10984 zend_compile_rope_add_ex(opline, result, j++, &last_const_node);
10985 last_const_node.op_type = IS_UNUSED;
10986 }
10987 opline = zend_compile_rope_add(result, j++, &elem_node);
10988 }
10989 }
10990
10991 if (j == 0) {
10992 result->op_type = IS_CONST;
10993 if (last_const_node.op_type == IS_CONST) {
10994 ZVAL_COPY_VALUE(&result->u.constant, &last_const_node.u.constant);
10995 } else {
10996 ZVAL_EMPTY_STRING(&result->u.constant);
10997 /* empty string */
10998 }
10999 CG(active_op_array)->last = reserved_op_number - 1;
11000 return;
11001 } else if (last_const_node.op_type == IS_CONST) {
11002 opline = &CG(active_op_array)->opcodes[reserved_op_number];
11003 opline = zend_compile_rope_add_ex(opline, result, j++, &last_const_node);
11004 }
11005 init_opline = CG(active_op_array)->opcodes + rope_init_lineno;
11006 zend_compile_rope_finalize(result, j, init_opline, opline);
11007 }
11008 /* }}} */
11009
zend_compile_magic_const(znode * result,zend_ast * ast)11010 static void zend_compile_magic_const(znode *result, zend_ast *ast) /* {{{ */
11011 {
11012 zend_op *opline;
11013
11014 if (zend_try_ct_eval_magic_const(&result->u.constant, ast)) {
11015 result->op_type = IS_CONST;
11016 return;
11017 }
11018
11019 ZEND_ASSERT(ast->attr == T_CLASS_C &&
11020 CG(active_class_entry) &&
11021 (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != 0);
11022
11023 opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
11024 opline->op1.num = ZEND_FETCH_CLASS_SELF;
11025 }
11026 /* }}} */
11027
zend_is_allowed_in_const_expr(zend_ast_kind kind)11028 static bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */
11029 {
11030 return kind == ZEND_AST_ZVAL || kind == ZEND_AST_BINARY_OP
11031 || kind == ZEND_AST_GREATER || kind == ZEND_AST_GREATER_EQUAL
11032 || kind == ZEND_AST_AND || kind == ZEND_AST_OR
11033 || kind == ZEND_AST_UNARY_OP
11034 || kind == ZEND_AST_UNARY_PLUS || kind == ZEND_AST_UNARY_MINUS
11035 || kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM
11036 || kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM
11037 || kind == ZEND_AST_UNPACK
11038 || kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST
11039 || kind == ZEND_AST_CLASS_NAME
11040 || kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE
11041 || kind == ZEND_AST_CONST_ENUM_INIT
11042 || kind == ZEND_AST_NEW || kind == ZEND_AST_ARG_LIST
11043 || kind == ZEND_AST_NAMED_ARG
11044 || kind == ZEND_AST_PROP || kind == ZEND_AST_NULLSAFE_PROP;
11045 }
11046 /* }}} */
11047
zend_compile_const_expr_class_const(zend_ast ** ast_ptr)11048 static void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */
11049 {
11050 zend_ast *ast = *ast_ptr;
11051 zend_ast *class_ast = ast->child[0];
11052 zend_string *class_name;
11053 int fetch_type;
11054
11055 if (class_ast->kind != ZEND_AST_ZVAL) {
11056 zend_error_noreturn(E_COMPILE_ERROR,
11057 "Dynamic class names are not allowed in compile-time class constant references");
11058 }
11059 if (Z_TYPE_P(zend_ast_get_zval(class_ast)) != IS_STRING) {
11060 zend_throw_error(NULL, "Class name must be a valid object or a string");
11061 }
11062
11063 class_name = zend_ast_get_str(class_ast);
11064 fetch_type = zend_get_class_fetch_type(class_name);
11065
11066 if (ZEND_FETCH_CLASS_STATIC == fetch_type) {
11067 zend_error_noreturn(E_COMPILE_ERROR,
11068 "\"static::\" is not allowed in compile-time constants");
11069 }
11070
11071 if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
11072 zend_string *tmp = zend_resolve_class_name_ast(class_ast);
11073
11074 zend_string_release_ex(class_name, 0);
11075 if (tmp != class_name) {
11076 zval *zv = zend_ast_get_zval(class_ast);
11077 ZVAL_STR(zv, tmp);
11078 class_ast->attr = ZEND_NAME_FQ;
11079 }
11080 }
11081
11082 ast->attr |= ZEND_FETCH_CLASS_EXCEPTION;
11083 }
11084 /* }}} */
11085
zend_compile_const_expr_class_name(zend_ast ** ast_ptr)11086 static void zend_compile_const_expr_class_name(zend_ast **ast_ptr) /* {{{ */
11087 {
11088 zend_ast *ast = *ast_ptr;
11089 zend_ast *class_ast = ast->child[0];
11090 if (class_ast->kind != ZEND_AST_ZVAL) {
11091 zend_error_noreturn(E_COMPILE_ERROR,
11092 "(expression)::class cannot be used in constant expressions");
11093 }
11094
11095 zend_string *class_name = zend_ast_get_str(class_ast);
11096 uint32_t fetch_type = zend_get_class_fetch_type(class_name);
11097
11098 switch (fetch_type) {
11099 case ZEND_FETCH_CLASS_SELF:
11100 case ZEND_FETCH_CLASS_PARENT:
11101 /* For the const-eval representation store the fetch type instead of the name. */
11102 zend_string_release(class_name);
11103 ast->child[0] = NULL;
11104 ast->attr = fetch_type;
11105 return;
11106 case ZEND_FETCH_CLASS_STATIC:
11107 zend_error_noreturn(E_COMPILE_ERROR,
11108 "static::class cannot be used for compile-time class name resolution");
11109 return;
11110 EMPTY_SWITCH_DEFAULT_CASE()
11111 }
11112 }
11113
zend_compile_const_expr_const(zend_ast ** ast_ptr)11114 static void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */
11115 {
11116 zend_ast *ast = *ast_ptr;
11117 zend_ast *name_ast = ast->child[0];
11118 zend_string *orig_name = zend_ast_get_str(name_ast);
11119 bool is_fully_qualified;
11120 zval result;
11121 zend_string *resolved_name;
11122
11123 CG(zend_lineno) = zend_ast_get_lineno(ast);
11124
11125 resolved_name = zend_resolve_const_name(
11126 orig_name, name_ast->attr, &is_fully_qualified);
11127
11128 if (zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified)) {
11129 zend_string_release_ex(resolved_name, 0);
11130 zend_ast_destroy(ast);
11131 *ast_ptr = zend_ast_create_zval(&result);
11132 return;
11133 }
11134
11135 zend_ast_destroy(ast);
11136 *ast_ptr = zend_ast_create_constant(resolved_name,
11137 !is_fully_qualified && FC(current_namespace) ? IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE : 0);
11138 }
11139 /* }}} */
11140
zend_compile_const_expr_magic_const(zend_ast ** ast_ptr)11141 static void zend_compile_const_expr_magic_const(zend_ast **ast_ptr) /* {{{ */
11142 {
11143 zend_ast *ast = *ast_ptr;
11144
11145 /* Other cases already resolved by constant folding */
11146 ZEND_ASSERT(ast->attr == T_CLASS_C);
11147
11148 zend_ast_destroy(ast);
11149 *ast_ptr = zend_ast_create(ZEND_AST_CONSTANT_CLASS);
11150 }
11151 /* }}} */
11152
zend_compile_const_expr_new(zend_ast ** ast_ptr)11153 static void zend_compile_const_expr_new(zend_ast **ast_ptr)
11154 {
11155 zend_ast *class_ast = (*ast_ptr)->child[0];
11156 if (class_ast->kind == ZEND_AST_CLASS) {
11157 zend_error_noreturn(E_COMPILE_ERROR,
11158 "Cannot use anonymous class in constant expression");
11159 }
11160 if (class_ast->kind != ZEND_AST_ZVAL) {
11161 zend_error_noreturn(E_COMPILE_ERROR,
11162 "Cannot use dynamic class name in constant expression");
11163 }
11164
11165 zend_string *class_name = zend_resolve_class_name_ast(class_ast);
11166 int fetch_type = zend_get_class_fetch_type(class_name);
11167 if (ZEND_FETCH_CLASS_STATIC == fetch_type) {
11168 zend_error_noreturn(E_COMPILE_ERROR,
11169 "\"static\" is not allowed in compile-time constants");
11170 }
11171
11172 zval *class_ast_zv = zend_ast_get_zval(class_ast);
11173 zval_ptr_dtor_nogc(class_ast_zv);
11174 ZVAL_STR(class_ast_zv, class_name);
11175 class_ast->attr = fetch_type << ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT;
11176 }
11177
zend_compile_const_expr_args(zend_ast ** ast_ptr)11178 static void zend_compile_const_expr_args(zend_ast **ast_ptr)
11179 {
11180 zend_ast_list *list = zend_ast_get_list(*ast_ptr);
11181 bool uses_named_args = false;
11182 for (uint32_t i = 0; i < list->children; i++) {
11183 zend_ast *arg = list->child[i];
11184 if (arg->kind == ZEND_AST_UNPACK) {
11185 zend_error_noreturn(E_COMPILE_ERROR,
11186 "Argument unpacking in constant expressions is not supported");
11187 }
11188 if (arg->kind == ZEND_AST_NAMED_ARG) {
11189 uses_named_args = true;
11190 } else if (uses_named_args) {
11191 zend_error_noreturn(E_COMPILE_ERROR,
11192 "Cannot use positional argument after named argument");
11193 }
11194 }
11195 if (uses_named_args) {
11196 list->attr = 1;
11197 }
11198 }
11199
11200 typedef struct {
11201 /* Whether the value of this expression may differ on each evaluation. */
11202 bool allow_dynamic;
11203 } const_expr_context;
11204
zend_compile_const_expr(zend_ast ** ast_ptr,void * context)11205 static void zend_compile_const_expr(zend_ast **ast_ptr, void *context) /* {{{ */
11206 {
11207 const_expr_context *ctx = (const_expr_context *) context;
11208 zend_ast *ast = *ast_ptr;
11209 if (ast == NULL || ast->kind == ZEND_AST_ZVAL) {
11210 return;
11211 }
11212
11213 if (!zend_is_allowed_in_const_expr(ast->kind)) {
11214 zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations");
11215 }
11216
11217 switch (ast->kind) {
11218 case ZEND_AST_CLASS_CONST:
11219 zend_compile_const_expr_class_const(ast_ptr);
11220 break;
11221 case ZEND_AST_CLASS_NAME:
11222 zend_compile_const_expr_class_name(ast_ptr);
11223 break;
11224 case ZEND_AST_CONST:
11225 zend_compile_const_expr_const(ast_ptr);
11226 break;
11227 case ZEND_AST_MAGIC_CONST:
11228 zend_compile_const_expr_magic_const(ast_ptr);
11229 break;
11230 case ZEND_AST_NEW:
11231 if (!ctx->allow_dynamic) {
11232 zend_error_noreturn(E_COMPILE_ERROR,
11233 "New expressions are not supported in this context");
11234 }
11235 zend_compile_const_expr_new(ast_ptr);
11236 break;
11237 case ZEND_AST_ARG_LIST:
11238 zend_compile_const_expr_args(ast_ptr);
11239 break;
11240 }
11241
11242 zend_ast_apply(ast, zend_compile_const_expr, context);
11243 }
11244 /* }}} */
11245
zend_const_expr_to_zval(zval * result,zend_ast ** ast_ptr,bool allow_dynamic)11246 void zend_const_expr_to_zval(zval *result, zend_ast **ast_ptr, bool allow_dynamic) /* {{{ */
11247 {
11248 const_expr_context context;
11249 context.allow_dynamic = allow_dynamic;
11250
11251 zend_eval_const_expr(ast_ptr);
11252 zend_compile_const_expr(ast_ptr, &context);
11253 if ((*ast_ptr)->kind != ZEND_AST_ZVAL) {
11254 /* Replace with compiled AST zval representation. */
11255 zval ast_zv;
11256 ZVAL_AST(&ast_zv, zend_ast_copy(*ast_ptr));
11257 zend_ast_destroy(*ast_ptr);
11258 *ast_ptr = zend_ast_create_zval(&ast_zv);
11259 }
11260 ZVAL_COPY(result, zend_ast_get_zval(*ast_ptr));
11261 }
11262 /* }}} */
11263
11264 /* Same as compile_stmt, but with early binding */
zend_compile_top_stmt(zend_ast * ast)11265 void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
11266 {
11267 if (!ast) {
11268 return;
11269 }
11270
11271 if (ast->kind == ZEND_AST_STMT_LIST) {
11272 zend_ast_list *list = zend_ast_get_list(ast);
11273 uint32_t i;
11274 for (i = 0; i < list->children; ++i) {
11275 zend_compile_top_stmt(list->child[i]);
11276 }
11277 return;
11278 }
11279
11280 if (ast->kind == ZEND_AST_FUNC_DECL) {
11281 CG(zend_lineno) = ast->lineno;
11282 zend_compile_func_decl(NULL, ast, 1);
11283 CG(zend_lineno) = ((zend_ast_decl *) ast)->end_lineno;
11284 } else if (ast->kind == ZEND_AST_CLASS) {
11285 CG(zend_lineno) = ast->lineno;
11286 zend_compile_class_decl(NULL, ast, 1);
11287 CG(zend_lineno) = ((zend_ast_decl *) ast)->end_lineno;
11288 } else {
11289 zend_compile_stmt(ast);
11290 }
11291 if (ast->kind != ZEND_AST_NAMESPACE && ast->kind != ZEND_AST_HALT_COMPILER) {
11292 zend_verify_namespace();
11293 }
11294 }
11295 /* }}} */
11296
zend_compile_stmt(zend_ast * ast)11297 static void zend_compile_stmt(zend_ast *ast) /* {{{ */
11298 {
11299 if (!ast) {
11300 return;
11301 }
11302
11303 CG(zend_lineno) = ast->lineno;
11304
11305 if ((CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT) && !zend_is_unticked_stmt(ast)) {
11306 zend_do_extended_stmt();
11307 }
11308
11309 switch (ast->kind) {
11310 case ZEND_AST_STMT_LIST:
11311 zend_compile_stmt_list(ast);
11312 break;
11313 case ZEND_AST_GLOBAL:
11314 zend_compile_global_var(ast);
11315 break;
11316 case ZEND_AST_STATIC:
11317 zend_compile_static_var(ast);
11318 break;
11319 case ZEND_AST_UNSET:
11320 zend_compile_unset(ast);
11321 break;
11322 case ZEND_AST_RETURN:
11323 zend_compile_return(ast);
11324 break;
11325 case ZEND_AST_ECHO:
11326 zend_compile_echo(ast);
11327 break;
11328 case ZEND_AST_BREAK:
11329 case ZEND_AST_CONTINUE:
11330 zend_compile_break_continue(ast);
11331 break;
11332 case ZEND_AST_GOTO:
11333 zend_compile_goto(ast);
11334 break;
11335 case ZEND_AST_LABEL:
11336 zend_compile_label(ast);
11337 break;
11338 case ZEND_AST_WHILE:
11339 zend_compile_while(ast);
11340 break;
11341 case ZEND_AST_DO_WHILE:
11342 zend_compile_do_while(ast);
11343 break;
11344 case ZEND_AST_FOR:
11345 zend_compile_for(ast);
11346 break;
11347 case ZEND_AST_FOREACH:
11348 zend_compile_foreach(ast);
11349 break;
11350 case ZEND_AST_IF:
11351 zend_compile_if(ast);
11352 break;
11353 case ZEND_AST_SWITCH:
11354 zend_compile_switch(ast);
11355 break;
11356 case ZEND_AST_TRY:
11357 zend_compile_try(ast);
11358 break;
11359 case ZEND_AST_DECLARE:
11360 zend_compile_declare(ast);
11361 break;
11362 case ZEND_AST_FUNC_DECL:
11363 case ZEND_AST_METHOD:
11364 zend_compile_func_decl(NULL, ast, 0);
11365 break;
11366 case ZEND_AST_ENUM_CASE:
11367 zend_compile_enum_case(ast);
11368 break;
11369 case ZEND_AST_PROP_GROUP:
11370 zend_compile_prop_group(ast);
11371 break;
11372 case ZEND_AST_CLASS_CONST_GROUP:
11373 zend_compile_class_const_group(ast);
11374 break;
11375 case ZEND_AST_USE_TRAIT:
11376 zend_compile_use_trait(ast);
11377 break;
11378 case ZEND_AST_CLASS:
11379 zend_compile_class_decl(NULL, ast, 0);
11380 break;
11381 case ZEND_AST_GROUP_USE:
11382 zend_compile_group_use(ast);
11383 break;
11384 case ZEND_AST_USE:
11385 zend_compile_use(ast);
11386 break;
11387 case ZEND_AST_CONST_DECL:
11388 zend_compile_const_decl(ast);
11389 break;
11390 case ZEND_AST_NAMESPACE:
11391 zend_compile_namespace(ast);
11392 break;
11393 case ZEND_AST_HALT_COMPILER:
11394 zend_compile_halt_compiler(ast);
11395 break;
11396 case ZEND_AST_THROW:
11397 zend_compile_expr(NULL, ast);
11398 break;
11399 default:
11400 {
11401 znode result;
11402 zend_compile_expr(&result, ast);
11403 zend_do_free(&result);
11404 }
11405 }
11406
11407 if (FC(declarables).ticks && !zend_is_unticked_stmt(ast)) {
11408 zend_emit_tick();
11409 }
11410 }
11411 /* }}} */
11412
zend_compile_expr_inner(znode * result,zend_ast * ast)11413 static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
11414 {
11415 /* CG(zend_lineno) = ast->lineno; */
11416 CG(zend_lineno) = zend_ast_get_lineno(ast);
11417
11418 if (CG(memoize_mode) != ZEND_MEMOIZE_NONE) {
11419 zend_compile_memoized_expr(result, ast);
11420 return;
11421 }
11422
11423 switch (ast->kind) {
11424 case ZEND_AST_ZVAL:
11425 ZVAL_COPY(&result->u.constant, zend_ast_get_zval(ast));
11426 result->op_type = IS_CONST;
11427 return;
11428 case ZEND_AST_ZNODE:
11429 *result = *zend_ast_get_znode(ast);
11430 return;
11431 case ZEND_AST_VAR:
11432 case ZEND_AST_DIM:
11433 case ZEND_AST_PROP:
11434 case ZEND_AST_NULLSAFE_PROP:
11435 case ZEND_AST_STATIC_PROP:
11436 case ZEND_AST_CALL:
11437 case ZEND_AST_METHOD_CALL:
11438 case ZEND_AST_NULLSAFE_METHOD_CALL:
11439 case ZEND_AST_STATIC_CALL:
11440 case ZEND_AST_PARENT_PROPERTY_HOOK_CALL:
11441 zend_compile_var(result, ast, BP_VAR_R, 0);
11442 return;
11443 case ZEND_AST_ASSIGN:
11444 zend_compile_assign(result, ast);
11445 return;
11446 case ZEND_AST_ASSIGN_REF:
11447 zend_compile_assign_ref(result, ast);
11448 return;
11449 case ZEND_AST_NEW:
11450 zend_compile_new(result, ast);
11451 return;
11452 case ZEND_AST_CLONE:
11453 zend_compile_clone(result, ast);
11454 return;
11455 case ZEND_AST_ASSIGN_OP:
11456 zend_compile_compound_assign(result, ast);
11457 return;
11458 case ZEND_AST_BINARY_OP:
11459 zend_compile_binary_op(result, ast);
11460 return;
11461 case ZEND_AST_GREATER:
11462 case ZEND_AST_GREATER_EQUAL:
11463 zend_compile_greater(result, ast);
11464 return;
11465 case ZEND_AST_UNARY_OP:
11466 zend_compile_unary_op(result, ast);
11467 return;
11468 case ZEND_AST_UNARY_PLUS:
11469 case ZEND_AST_UNARY_MINUS:
11470 zend_compile_unary_pm(result, ast);
11471 return;
11472 case ZEND_AST_AND:
11473 case ZEND_AST_OR:
11474 zend_compile_short_circuiting(result, ast);
11475 return;
11476 case ZEND_AST_POST_INC:
11477 case ZEND_AST_POST_DEC:
11478 zend_compile_post_incdec(result, ast);
11479 return;
11480 case ZEND_AST_PRE_INC:
11481 case ZEND_AST_PRE_DEC:
11482 zend_compile_pre_incdec(result, ast);
11483 return;
11484 case ZEND_AST_CAST:
11485 zend_compile_cast(result, ast);
11486 return;
11487 case ZEND_AST_CONDITIONAL:
11488 zend_compile_conditional(result, ast);
11489 return;
11490 case ZEND_AST_COALESCE:
11491 zend_compile_coalesce(result, ast);
11492 return;
11493 case ZEND_AST_ASSIGN_COALESCE:
11494 zend_compile_assign_coalesce(result, ast);
11495 return;
11496 case ZEND_AST_PRINT:
11497 zend_compile_print(result, ast);
11498 return;
11499 case ZEND_AST_YIELD:
11500 zend_compile_yield(result, ast);
11501 return;
11502 case ZEND_AST_YIELD_FROM:
11503 zend_compile_yield_from(result, ast);
11504 return;
11505 case ZEND_AST_INSTANCEOF:
11506 zend_compile_instanceof(result, ast);
11507 return;
11508 case ZEND_AST_INCLUDE_OR_EVAL:
11509 zend_compile_include_or_eval(result, ast);
11510 return;
11511 case ZEND_AST_ISSET:
11512 case ZEND_AST_EMPTY:
11513 zend_compile_isset_or_empty(result, ast);
11514 return;
11515 case ZEND_AST_SILENCE:
11516 zend_compile_silence(result, ast);
11517 return;
11518 case ZEND_AST_SHELL_EXEC:
11519 zend_compile_shell_exec(result, ast);
11520 return;
11521 case ZEND_AST_ARRAY:
11522 zend_compile_array(result, ast);
11523 return;
11524 case ZEND_AST_CONST:
11525 zend_compile_const(result, ast);
11526 return;
11527 case ZEND_AST_CLASS_CONST:
11528 zend_compile_class_const(result, ast);
11529 return;
11530 case ZEND_AST_CLASS_NAME:
11531 zend_compile_class_name(result, ast);
11532 return;
11533 case ZEND_AST_ENCAPS_LIST:
11534 zend_compile_encaps_list(result, ast);
11535 return;
11536 case ZEND_AST_MAGIC_CONST:
11537 zend_compile_magic_const(result, ast);
11538 return;
11539 case ZEND_AST_CLOSURE:
11540 case ZEND_AST_ARROW_FUNC:
11541 zend_compile_func_decl(result, ast, 0);
11542 return;
11543 case ZEND_AST_THROW:
11544 zend_compile_throw(result, ast);
11545 return;
11546 case ZEND_AST_MATCH:
11547 zend_compile_match(result, ast);
11548 return;
11549 default:
11550 ZEND_ASSERT(0 /* not supported */);
11551 }
11552 }
11553 /* }}} */
11554
zend_compile_expr(znode * result,zend_ast * ast)11555 static void zend_compile_expr(znode *result, zend_ast *ast)
11556 {
11557 zend_check_stack_limit();
11558
11559 uint32_t checkpoint = zend_short_circuiting_checkpoint();
11560 zend_compile_expr_inner(result, ast);
11561 zend_short_circuiting_commit(checkpoint, result, ast);
11562 }
11563
zend_compile_var_inner(znode * result,zend_ast * ast,uint32_t type,bool by_ref)11564 static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t type, bool by_ref)
11565 {
11566 CG(zend_lineno) = zend_ast_get_lineno(ast);
11567
11568 if (CG(memoize_mode) != ZEND_MEMOIZE_NONE) {
11569 switch (ast->kind) {
11570 case ZEND_AST_CALL:
11571 case ZEND_AST_METHOD_CALL:
11572 case ZEND_AST_NULLSAFE_METHOD_CALL:
11573 case ZEND_AST_STATIC_CALL:
11574 zend_compile_memoized_expr(result, ast);
11575 /* This might not actually produce an opcode, e.g. for expressions evaluated at comptime. */
11576 return NULL;
11577 }
11578 }
11579
11580 switch (ast->kind) {
11581 case ZEND_AST_VAR:
11582 return zend_compile_simple_var(result, ast, type, 0);
11583 case ZEND_AST_DIM:
11584 return zend_compile_dim(result, ast, type, by_ref);
11585 case ZEND_AST_PROP:
11586 case ZEND_AST_NULLSAFE_PROP:
11587 return zend_compile_prop(result, ast, type, by_ref);
11588 case ZEND_AST_STATIC_PROP:
11589 return zend_compile_static_prop(result, ast, type, by_ref, 0);
11590 case ZEND_AST_CALL:
11591 zend_compile_call(result, ast, type);
11592 return NULL;
11593 case ZEND_AST_PARENT_PROPERTY_HOOK_CALL:
11594 zend_compile_parent_property_hook_call(result, ast, type);
11595 return NULL;
11596 case ZEND_AST_METHOD_CALL:
11597 case ZEND_AST_NULLSAFE_METHOD_CALL:
11598 zend_compile_method_call(result, ast, type);
11599 return NULL;
11600 case ZEND_AST_STATIC_CALL:
11601 zend_compile_static_call(result, ast, type);
11602 return NULL;
11603 case ZEND_AST_ZNODE:
11604 *result = *zend_ast_get_znode(ast);
11605 return NULL;
11606 default:
11607 if (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) {
11608 zend_error_noreturn(E_COMPILE_ERROR,
11609 "Cannot use temporary expression in write context");
11610 }
11611
11612 zend_compile_expr(result, ast);
11613 return NULL;
11614 }
11615 }
11616
zend_compile_var(znode * result,zend_ast * ast,uint32_t type,bool by_ref)11617 static zend_op *zend_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
11618 {
11619 uint32_t checkpoint = zend_short_circuiting_checkpoint();
11620 zend_op *opcode = zend_compile_var_inner(result, ast, type, by_ref);
11621 zend_short_circuiting_commit(checkpoint, result, ast);
11622 return opcode;
11623 }
11624
zend_delayed_compile_var(znode * result,zend_ast * ast,uint32_t type,bool by_ref)11625 static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
11626 {
11627 switch (ast->kind) {
11628 case ZEND_AST_VAR:
11629 return zend_compile_simple_var(result, ast, type, 1);
11630 case ZEND_AST_DIM:
11631 return zend_delayed_compile_dim(result, ast, type, by_ref);
11632 case ZEND_AST_PROP:
11633 case ZEND_AST_NULLSAFE_PROP:
11634 {
11635 zend_op *opline = zend_delayed_compile_prop(result, ast, type);
11636 if (by_ref) {
11637 opline->extended_value |= ZEND_FETCH_REF;
11638 }
11639 return opline;
11640 }
11641 case ZEND_AST_STATIC_PROP:
11642 return zend_compile_static_prop(result, ast, type, by_ref, 1);
11643 default:
11644 return zend_compile_var(result, ast, type, 0);
11645 }
11646 }
11647 /* }}} */
11648
zend_eval_const_expr(zend_ast ** ast_ptr)11649 static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
11650 {
11651 zend_ast *ast = *ast_ptr;
11652 zval result;
11653
11654 if (!ast) {
11655 return;
11656 }
11657
11658 zend_check_stack_limit();
11659
11660 switch (ast->kind) {
11661 case ZEND_AST_BINARY_OP:
11662 zend_eval_const_expr(&ast->child[0]);
11663 zend_eval_const_expr(&ast->child[1]);
11664 if (ast->child[0]->kind != ZEND_AST_ZVAL || ast->child[1]->kind != ZEND_AST_ZVAL) {
11665 return;
11666 }
11667
11668 if (!zend_try_ct_eval_binary_op(&result, ast->attr,
11669 zend_ast_get_zval(ast->child[0]), zend_ast_get_zval(ast->child[1]))
11670 ) {
11671 return;
11672 }
11673 break;
11674 case ZEND_AST_GREATER:
11675 case ZEND_AST_GREATER_EQUAL:
11676 zend_eval_const_expr(&ast->child[0]);
11677 zend_eval_const_expr(&ast->child[1]);
11678 if (ast->child[0]->kind != ZEND_AST_ZVAL || ast->child[1]->kind != ZEND_AST_ZVAL) {
11679 return;
11680 }
11681
11682 zend_ct_eval_greater(&result, ast->kind,
11683 zend_ast_get_zval(ast->child[0]), zend_ast_get_zval(ast->child[1]));
11684 break;
11685 case ZEND_AST_AND:
11686 case ZEND_AST_OR:
11687 {
11688 bool child0_is_true, child1_is_true;
11689 zend_eval_const_expr(&ast->child[0]);
11690 zend_eval_const_expr(&ast->child[1]);
11691 if (ast->child[0]->kind != ZEND_AST_ZVAL) {
11692 return;
11693 }
11694
11695 child0_is_true = zend_is_true(zend_ast_get_zval(ast->child[0]));
11696 if (child0_is_true == (ast->kind == ZEND_AST_OR)) {
11697 ZVAL_BOOL(&result, ast->kind == ZEND_AST_OR);
11698 break;
11699 }
11700
11701 if (ast->child[1]->kind != ZEND_AST_ZVAL) {
11702 return;
11703 }
11704
11705 child1_is_true = zend_is_true(zend_ast_get_zval(ast->child[1]));
11706 if (ast->kind == ZEND_AST_OR) {
11707 ZVAL_BOOL(&result, child0_is_true || child1_is_true);
11708 } else {
11709 ZVAL_BOOL(&result, child0_is_true && child1_is_true);
11710 }
11711 break;
11712 }
11713 case ZEND_AST_UNARY_OP:
11714 zend_eval_const_expr(&ast->child[0]);
11715 if (ast->child[0]->kind != ZEND_AST_ZVAL) {
11716 return;
11717 }
11718
11719 if (!zend_try_ct_eval_unary_op(&result, ast->attr, zend_ast_get_zval(ast->child[0]))) {
11720 return;
11721 }
11722 break;
11723 case ZEND_AST_UNARY_PLUS:
11724 case ZEND_AST_UNARY_MINUS:
11725 zend_eval_const_expr(&ast->child[0]);
11726 if (ast->child[0]->kind != ZEND_AST_ZVAL) {
11727 return;
11728 }
11729
11730 if (!zend_try_ct_eval_unary_pm(&result, ast->kind, zend_ast_get_zval(ast->child[0]))) {
11731 return;
11732 }
11733 break;
11734 case ZEND_AST_COALESCE:
11735 /* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
11736 if (ast->child[0]->kind == ZEND_AST_DIM) {
11737 ast->child[0]->attr |= ZEND_DIM_IS;
11738 }
11739 zend_eval_const_expr(&ast->child[0]);
11740
11741 if (ast->child[0]->kind != ZEND_AST_ZVAL) {
11742 /* ensure everything was compile-time evaluated at least once */
11743 zend_eval_const_expr(&ast->child[1]);
11744 return;
11745 }
11746
11747 if (Z_TYPE_P(zend_ast_get_zval(ast->child[0])) == IS_NULL) {
11748 zend_eval_const_expr(&ast->child[1]);
11749 *ast_ptr = ast->child[1];
11750 ast->child[1] = NULL;
11751 zend_ast_destroy(ast);
11752 } else {
11753 *ast_ptr = ast->child[0];
11754 ast->child[0] = NULL;
11755 zend_ast_destroy(ast);
11756 }
11757 return;
11758 case ZEND_AST_CONDITIONAL:
11759 {
11760 zend_ast **child, *child_ast;
11761 zend_eval_const_expr(&ast->child[0]);
11762 if (ast->child[0]->kind != ZEND_AST_ZVAL) {
11763 /* ensure everything was compile-time evaluated at least once */
11764 if (ast->child[1]) {
11765 zend_eval_const_expr(&ast->child[1]);
11766 }
11767 zend_eval_const_expr(&ast->child[2]);
11768 return;
11769 }
11770
11771 child = &ast->child[2 - zend_is_true(zend_ast_get_zval(ast->child[0]))];
11772 if (*child == NULL) {
11773 child--;
11774 }
11775 child_ast = *child;
11776 *child = NULL;
11777 zend_ast_destroy(ast);
11778 *ast_ptr = child_ast;
11779 zend_eval_const_expr(ast_ptr);
11780 return;
11781 }
11782 case ZEND_AST_DIM:
11783 {
11784 /* constant expression should be always read context ... */
11785 zval *container, *dim;
11786
11787 if (ast->child[1] == NULL) {
11788 zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
11789 }
11790
11791 /* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
11792 if ((ast->attr & ZEND_DIM_IS) && ast->child[0]->kind == ZEND_AST_DIM) {
11793 ast->child[0]->attr |= ZEND_DIM_IS;
11794 }
11795
11796 zend_eval_const_expr(&ast->child[0]);
11797 zend_eval_const_expr(&ast->child[1]);
11798 if (ast->child[0]->kind != ZEND_AST_ZVAL || ast->child[1]->kind != ZEND_AST_ZVAL) {
11799 return;
11800 }
11801
11802 container = zend_ast_get_zval(ast->child[0]);
11803 dim = zend_ast_get_zval(ast->child[1]);
11804
11805 if (Z_TYPE_P(container) == IS_ARRAY) {
11806 zval *el;
11807 if (Z_TYPE_P(dim) == IS_LONG) {
11808 el = zend_hash_index_find(Z_ARR_P(container), Z_LVAL_P(dim));
11809 if (el) {
11810 ZVAL_COPY(&result, el);
11811 } else {
11812 return;
11813 }
11814 } else if (Z_TYPE_P(dim) == IS_STRING) {
11815 el = zend_symtable_find(Z_ARR_P(container), Z_STR_P(dim));
11816 if (el) {
11817 ZVAL_COPY(&result, el);
11818 } else {
11819 return;
11820 }
11821 } else {
11822 return; /* warning... handle at runtime */
11823 }
11824 } else if (Z_TYPE_P(container) == IS_STRING) {
11825 zend_long offset;
11826 uint8_t c;
11827 if (Z_TYPE_P(dim) == IS_LONG) {
11828 offset = Z_LVAL_P(dim);
11829 } else if (Z_TYPE_P(dim) != IS_STRING || is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, 1) != IS_LONG) {
11830 return;
11831 }
11832 if (offset < 0 || (size_t)offset >= Z_STRLEN_P(container)) {
11833 return;
11834 }
11835 c = (uint8_t) Z_STRVAL_P(container)[offset];
11836 ZVAL_CHAR(&result, c);
11837 } else if (Z_TYPE_P(container) <= IS_FALSE) {
11838 return; /* warning... handle at runtime */
11839 } else {
11840 return;
11841 }
11842 break;
11843 }
11844 case ZEND_AST_ARRAY:
11845 if (!zend_try_ct_eval_array(&result, ast)) {
11846 return;
11847 }
11848 break;
11849 case ZEND_AST_MAGIC_CONST:
11850 if (!zend_try_ct_eval_magic_const(&result, ast)) {
11851 return;
11852 }
11853 break;
11854 case ZEND_AST_CONST:
11855 {
11856 zend_ast *name_ast = ast->child[0];
11857 bool is_fully_qualified;
11858 zend_string *resolved_name = zend_resolve_const_name(
11859 zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified);
11860
11861 if (!zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified)) {
11862 zend_string_release_ex(resolved_name, 0);
11863 return;
11864 }
11865
11866 zend_string_release_ex(resolved_name, 0);
11867 break;
11868 }
11869 case ZEND_AST_CLASS_CONST:
11870 {
11871 zend_ast *class_ast;
11872 zend_ast *name_ast;
11873 zend_string *resolved_name;
11874
11875 zend_eval_const_expr(&ast->child[0]);
11876 zend_eval_const_expr(&ast->child[1]);
11877
11878 if (UNEXPECTED(ast->child[1]->kind != ZEND_AST_ZVAL
11879 || Z_TYPE_P(zend_ast_get_zval(ast->child[1])) != IS_STRING)) {
11880 return;
11881 }
11882
11883 class_ast = ast->child[0];
11884 name_ast = ast->child[1];
11885
11886 if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) {
11887 return;
11888 }
11889
11890 resolved_name = zend_resolve_class_name_ast(class_ast);
11891 if (!zend_try_ct_eval_class_const(&result, resolved_name, zend_ast_get_str(name_ast))) {
11892 zend_string_release_ex(resolved_name, 0);
11893 return;
11894 }
11895
11896 zend_string_release_ex(resolved_name, 0);
11897 break;
11898 }
11899 case ZEND_AST_CLASS_NAME:
11900 {
11901 zend_ast *class_ast = ast->child[0];
11902 if (!zend_try_compile_const_expr_resolve_class_name(&result, class_ast)) {
11903 return;
11904 }
11905 break;
11906 }
11907 // TODO: We should probably use zend_ast_apply to recursively walk nodes without
11908 // special handling. It is required that all nodes that are part of a const expr
11909 // are visited. Probably we should be distinguishing evaluation of const expr and
11910 // normal exprs here.
11911 case ZEND_AST_ARG_LIST:
11912 {
11913 zend_ast_list *list = zend_ast_get_list(ast);
11914 for (uint32_t i = 0; i < list->children; i++) {
11915 zend_eval_const_expr(&list->child[i]);
11916 }
11917 return;
11918 }
11919 case ZEND_AST_NEW:
11920 zend_eval_const_expr(&ast->child[0]);
11921 zend_eval_const_expr(&ast->child[1]);
11922 return;
11923 case ZEND_AST_NAMED_ARG:
11924 zend_eval_const_expr(&ast->child[1]);
11925 return;
11926 case ZEND_AST_CONST_ENUM_INIT:
11927 zend_eval_const_expr(&ast->child[2]);
11928 return;
11929 case ZEND_AST_PROP:
11930 case ZEND_AST_NULLSAFE_PROP:
11931 zend_eval_const_expr(&ast->child[0]);
11932 zend_eval_const_expr(&ast->child[1]);
11933 return;
11934 default:
11935 return;
11936 }
11937
11938 zend_ast_destroy(ast);
11939 *ast_ptr = zend_ast_create_zval(&result);
11940 }
11941 /* }}} */
11942