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