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