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