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