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 | Dmitry Stogov <dmitry@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include <stdio.h>
22
23 #include "zend.h"
24 #include "zend_alloc.h"
25 #include "zend_compile.h"
26 #include "zend_extensions.h"
27 #include "zend_API.h"
28 #include "zend_sort.h"
29
30 #include "zend_vm.h"
31
zend_extension_op_array_ctor_handler(zend_extension * extension,zend_op_array * op_array)32 static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array)
33 {
34 if (extension->op_array_ctor) {
35 extension->op_array_ctor(op_array);
36 }
37 }
38
zend_extension_op_array_dtor_handler(zend_extension * extension,zend_op_array * op_array)39 static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array)
40 {
41 if (extension->op_array_dtor) {
42 extension->op_array_dtor(op_array);
43 }
44 }
45
init_op_array(zend_op_array * op_array,zend_uchar type,int initial_ops_size)46 void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size)
47 {
48 op_array->type = type;
49 op_array->arg_flags[0] = 0;
50 op_array->arg_flags[1] = 0;
51 op_array->arg_flags[2] = 0;
52
53 op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
54 *op_array->refcount = 1;
55 op_array->last = 0;
56 op_array->opcodes = emalloc(initial_ops_size * sizeof(zend_op));
57
58 op_array->last_var = 0;
59 op_array->vars = NULL;
60
61 op_array->T = 0;
62
63 op_array->function_name = NULL;
64 op_array->filename = zend_get_compiled_filename();
65 op_array->doc_comment = NULL;
66
67 op_array->arg_info = NULL;
68 op_array->num_args = 0;
69 op_array->required_num_args = 0;
70
71 op_array->scope = NULL;
72 op_array->prototype = NULL;
73
74 op_array->live_range = NULL;
75 op_array->try_catch_array = NULL;
76 op_array->last_live_range = 0;
77
78 op_array->static_variables = NULL;
79 ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
80 op_array->last_try_catch = 0;
81
82 op_array->fn_flags = 0;
83
84 op_array->last_literal = 0;
85 op_array->literals = NULL;
86
87 ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
88 op_array->cache_size = zend_op_array_extension_handles * sizeof(void*);
89
90 memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
91
92 if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_CTOR) {
93 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array);
94 }
95 }
96
destroy_zend_function(zend_function * function)97 ZEND_API void destroy_zend_function(zend_function *function)
98 {
99 zval tmp;
100
101 ZVAL_PTR(&tmp, function);
102 zend_function_dtor(&tmp);
103 }
104
zend_free_internal_arg_info(zend_internal_function * function)105 void zend_free_internal_arg_info(zend_internal_function *function) {
106 if ((function->fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
107 function->arg_info) {
108
109 uint32_t i;
110 uint32_t num_args = function->num_args + 1;
111 zend_internal_arg_info *arg_info = function->arg_info - 1;
112
113 if (function->fn_flags & ZEND_ACC_VARIADIC) {
114 num_args++;
115 }
116 for (i = 0 ; i < num_args; i++) {
117 if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
118 zend_string_release_ex(ZEND_TYPE_NAME(arg_info[i].type), 1);
119 }
120 }
121 free(arg_info);
122 }
123 }
124
zend_function_dtor(zval * zv)125 ZEND_API void zend_function_dtor(zval *zv)
126 {
127 zend_function *function = Z_PTR_P(zv);
128
129 if (function->type == ZEND_USER_FUNCTION) {
130 ZEND_ASSERT(function->common.function_name);
131 destroy_op_array(&function->op_array);
132 /* op_arrays are allocated on arena, so we don't have to free them */
133 } else {
134 ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION);
135 ZEND_ASSERT(function->common.function_name);
136 zend_string_release_ex(function->common.function_name, 1);
137
138 /* For methods this will be called explicitly. */
139 if (!function->common.scope) {
140 zend_free_internal_arg_info(&function->internal_function);
141 }
142
143 if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) {
144 pefree(function, 1);
145 }
146 }
147 }
148
zend_cleanup_internal_class_data(zend_class_entry * ce)149 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce)
150 {
151 if (CE_STATIC_MEMBERS(ce)) {
152 zval *static_members = CE_STATIC_MEMBERS(ce);
153 zval *p = static_members;
154 zval *end = p + ce->default_static_members_count;
155 if (UNEXPECTED(ZEND_MAP_PTR(ce->static_members_table) == &ce->default_static_members_table)) {
156 /* Special case: If this is a static property on a dl'ed internal class, then the
157 * static property table and the default property table are the same. In this case we
158 * destroy the values here, but leave behind valid UNDEF zvals and don't free the
159 * table itself. */
160 while (p != end) {
161 if (UNEXPECTED(Z_ISREF_P(p))) {
162 zend_property_info *prop_info;
163 ZEND_REF_FOREACH_TYPE_SOURCES(Z_REF_P(p), prop_info) {
164 if (prop_info->ce == ce && p - static_members == prop_info->offset) {
165 ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info);
166 break; /* stop iteration here, the array might be realloc()'ed */
167 }
168 } ZEND_REF_FOREACH_TYPE_SOURCES_END();
169 }
170 i_zval_ptr_dtor(p);
171 ZVAL_UNDEF(p);
172 p++;
173 }
174 } else {
175 ZEND_MAP_PTR_SET(ce->static_members_table, NULL);
176 while (p != end) {
177 if (UNEXPECTED(Z_ISREF_P(p))) {
178 zend_property_info *prop_info;
179 ZEND_REF_FOREACH_TYPE_SOURCES(Z_REF_P(p), prop_info) {
180 if (prop_info->ce == ce && p - static_members == prop_info->offset) {
181 ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info);
182 break; /* stop iteration here, the array might be realloc()'ed */
183 }
184 } ZEND_REF_FOREACH_TYPE_SOURCES_END();
185 }
186 i_zval_ptr_dtor(p);
187 p++;
188 }
189 efree(static_members);
190 }
191 }
192 }
193
_destroy_zend_class_traits_info(zend_class_entry * ce)194 static void _destroy_zend_class_traits_info(zend_class_entry *ce)
195 {
196 uint32_t i;
197
198 for (i = 0; i < ce->num_traits; i++) {
199 zend_string_release_ex(ce->trait_names[i].name, 0);
200 zend_string_release_ex(ce->trait_names[i].lc_name, 0);
201 }
202 efree(ce->trait_names);
203
204 if (ce->trait_aliases) {
205 i = 0;
206 while (ce->trait_aliases[i]) {
207 if (ce->trait_aliases[i]->trait_method.method_name) {
208 zend_string_release_ex(ce->trait_aliases[i]->trait_method.method_name, 0);
209 }
210 if (ce->trait_aliases[i]->trait_method.class_name) {
211 zend_string_release_ex(ce->trait_aliases[i]->trait_method.class_name, 0);
212 }
213
214 if (ce->trait_aliases[i]->alias) {
215 zend_string_release_ex(ce->trait_aliases[i]->alias, 0);
216 }
217
218 efree(ce->trait_aliases[i]);
219 i++;
220 }
221
222 efree(ce->trait_aliases);
223 }
224
225 if (ce->trait_precedences) {
226 uint32_t j;
227
228 i = 0;
229 while (ce->trait_precedences[i]) {
230 zend_string_release_ex(ce->trait_precedences[i]->trait_method.method_name, 0);
231 zend_string_release_ex(ce->trait_precedences[i]->trait_method.class_name, 0);
232
233 for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
234 zend_string_release_ex(ce->trait_precedences[i]->exclude_class_names[j], 0);
235 }
236 efree(ce->trait_precedences[i]);
237 i++;
238 }
239 efree(ce->trait_precedences);
240 }
241 }
242
destroy_zend_class(zval * zv)243 ZEND_API void destroy_zend_class(zval *zv)
244 {
245 zend_property_info *prop_info;
246 zend_class_entry *ce = Z_PTR_P(zv);
247 zend_function *fn;
248
249 if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)) {
250 zend_op_array *op_array;
251
252 if (ce->default_static_members_count) {
253 zend_cleanup_internal_class_data(ce);
254 }
255 if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
256 ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
257 if (op_array->type == ZEND_USER_FUNCTION) {
258 destroy_op_array(op_array);
259 }
260 } ZEND_HASH_FOREACH_END();
261 }
262 return;
263 } else if (--ce->refcount > 0) {
264 return;
265 }
266 switch (ce->type) {
267 case ZEND_USER_CLASS:
268 if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) {
269 zend_string_release_ex(ce->parent_name, 0);
270 }
271 if (ce->default_properties_table) {
272 zval *p = ce->default_properties_table;
273 zval *end = p + ce->default_properties_count;
274
275 while (p != end) {
276 i_zval_ptr_dtor(p);
277 p++;
278 }
279 efree(ce->default_properties_table);
280 }
281 if (ce->default_static_members_table) {
282 zval *p = ce->default_static_members_table;
283 zval *end = p + ce->default_static_members_count;
284
285 while (p != end) {
286 if (UNEXPECTED(Z_ISREF_P(p))) {
287 zend_property_info *prop_info;
288 ZEND_REF_FOREACH_TYPE_SOURCES(Z_REF_P(p), prop_info) {
289 if (prop_info->ce == ce && p - ce->default_static_members_table == prop_info->offset) {
290 ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info);
291 break; /* stop iteration here, the array might be realloc()'ed */
292 }
293 } ZEND_REF_FOREACH_TYPE_SOURCES_END();
294 }
295 i_zval_ptr_dtor(p);
296 p++;
297 }
298 efree(ce->default_static_members_table);
299 }
300 ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
301 if (prop_info->ce == ce) {
302 zend_string_release_ex(prop_info->name, 0);
303 if (prop_info->doc_comment) {
304 zend_string_release_ex(prop_info->doc_comment, 0);
305 }
306 if (ZEND_TYPE_IS_NAME(prop_info->type)) {
307 zend_string_release(ZEND_TYPE_NAME(prop_info->type));
308 }
309 }
310 } ZEND_HASH_FOREACH_END();
311 zend_hash_destroy(&ce->properties_info);
312 zend_string_release_ex(ce->name, 0);
313 zend_hash_destroy(&ce->function_table);
314 if (zend_hash_num_elements(&ce->constants_table)) {
315 zend_class_constant *c;
316
317 ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
318 if (c->ce == ce) {
319 zval_ptr_dtor_nogc(&c->value);
320 if (c->doc_comment) {
321 zend_string_release_ex(c->doc_comment, 0);
322 }
323 }
324 } ZEND_HASH_FOREACH_END();
325 }
326 zend_hash_destroy(&ce->constants_table);
327 if (ce->num_interfaces > 0) {
328 if (!(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
329 uint32_t i;
330
331 for (i = 0; i < ce->num_interfaces; i++) {
332 zend_string_release_ex(ce->interface_names[i].name, 0);
333 zend_string_release_ex(ce->interface_names[i].lc_name, 0);
334 }
335 }
336 efree(ce->interfaces);
337 }
338 if (ce->info.user.doc_comment) {
339 zend_string_release_ex(ce->info.user.doc_comment, 0);
340 }
341
342 if (ce->num_traits > 0) {
343 _destroy_zend_class_traits_info(ce);
344 }
345
346 break;
347 case ZEND_INTERNAL_CLASS:
348 if (ce->default_properties_table) {
349 zval *p = ce->default_properties_table;
350 zval *end = p + ce->default_properties_count;
351
352 while (p != end) {
353 zval_internal_ptr_dtor(p);
354 p++;
355 }
356 free(ce->default_properties_table);
357 }
358 if (ce->default_static_members_table) {
359 zval *p = ce->default_static_members_table;
360 zval *end = p + ce->default_static_members_count;
361
362 while (p != end) {
363 zval_internal_ptr_dtor(p);
364 p++;
365 }
366 free(ce->default_static_members_table);
367 if (ZEND_MAP_PTR(ce->static_members_table) != &ce->default_static_members_table) {
368 zend_cleanup_internal_class_data(ce);
369 }
370 }
371 zend_hash_destroy(&ce->properties_info);
372 zend_string_release_ex(ce->name, 1);
373
374 /* TODO: eliminate this loop for classes without functions with arg_info */
375 ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
376 if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
377 fn->common.scope == ce) {
378 zend_free_internal_arg_info(&fn->internal_function);
379 }
380 } ZEND_HASH_FOREACH_END();
381
382 zend_hash_destroy(&ce->function_table);
383 if (zend_hash_num_elements(&ce->constants_table)) {
384 zend_class_constant *c;
385
386 ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
387 if (c->ce == ce) {
388 zval_internal_ptr_dtor(&c->value);
389 if (c->doc_comment) {
390 zend_string_release_ex(c->doc_comment, 1);
391 }
392 }
393 free(c);
394 } ZEND_HASH_FOREACH_END();
395 zend_hash_destroy(&ce->constants_table);
396 }
397 if (ce->iterator_funcs_ptr) {
398 free(ce->iterator_funcs_ptr);
399 }
400 if (ce->num_interfaces > 0) {
401 free(ce->interfaces);
402 }
403 if (ce->properties_info_table) {
404 free(ce->properties_info_table);
405 }
406 free(ce);
407 break;
408 }
409 }
410
zend_class_add_ref(zval * zv)411 void zend_class_add_ref(zval *zv)
412 {
413 zend_class_entry *ce = Z_PTR_P(zv);
414
415 if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
416 ce->refcount++;
417 }
418 }
419
destroy_op_array(zend_op_array * op_array)420 ZEND_API void destroy_op_array(zend_op_array *op_array)
421 {
422 uint32_t i;
423
424 if (op_array->static_variables) {
425 HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
426 if (ht && !(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
427 if (GC_DELREF(ht) == 0) {
428 zend_array_destroy(ht);
429 }
430 }
431 }
432
433 if ((op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE)
434 && ZEND_MAP_PTR(op_array->run_time_cache)) {
435 efree(ZEND_MAP_PTR(op_array->run_time_cache));
436 }
437
438 if (!op_array->refcount || --(*op_array->refcount) > 0) {
439 return;
440 }
441
442 efree_size(op_array->refcount, sizeof(*(op_array->refcount)));
443
444 if (op_array->vars) {
445 i = op_array->last_var;
446 while (i > 0) {
447 i--;
448 zend_string_release_ex(op_array->vars[i], 0);
449 }
450 efree(op_array->vars);
451 }
452
453 if (op_array->literals) {
454 zval *literal = op_array->literals;
455 zval *end = literal + op_array->last_literal;
456 while (literal < end) {
457 zval_ptr_dtor_nogc(literal);
458 literal++;
459 }
460 if (ZEND_USE_ABS_CONST_ADDR
461 || !(op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO)) {
462 efree(op_array->literals);
463 }
464 }
465 efree(op_array->opcodes);
466
467 if (op_array->function_name) {
468 zend_string_release_ex(op_array->function_name, 0);
469 }
470 if (op_array->doc_comment) {
471 zend_string_release_ex(op_array->doc_comment, 0);
472 }
473 if (op_array->live_range) {
474 efree(op_array->live_range);
475 }
476 if (op_array->try_catch_array) {
477 efree(op_array->try_catch_array);
478 }
479 if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_DTOR) {
480 if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
481 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
482 }
483 }
484 if (op_array->arg_info) {
485 uint32_t num_args = op_array->num_args;
486 zend_arg_info *arg_info = op_array->arg_info;
487
488 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
489 arg_info--;
490 num_args++;
491 }
492 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
493 num_args++;
494 }
495 for (i = 0 ; i < num_args; i++) {
496 if (arg_info[i].name) {
497 zend_string_release_ex(arg_info[i].name, 0);
498 }
499 if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
500 zend_string_release_ex(ZEND_TYPE_NAME(arg_info[i].type), 0);
501 }
502 }
503 efree(arg_info);
504 }
505 }
506
zend_update_extended_stmts(zend_op_array * op_array)507 static void zend_update_extended_stmts(zend_op_array *op_array)
508 {
509 zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
510
511 while (opline<end) {
512 if (opline->opcode == ZEND_EXT_STMT) {
513 if (opline+1<end) {
514 if ((opline+1)->opcode == ZEND_EXT_STMT) {
515 opline->opcode = ZEND_NOP;
516 opline++;
517 continue;
518 }
519 if (opline+1<end) {
520 opline->lineno = (opline+1)->lineno;
521 }
522 } else {
523 opline->opcode = ZEND_NOP;
524 }
525 }
526 opline++;
527 }
528 }
529
zend_extension_op_array_handler(zend_extension * extension,zend_op_array * op_array)530 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array)
531 {
532 if (extension->op_array_handler) {
533 extension->op_array_handler(op_array);
534 }
535 }
536
zend_check_finally_breakout(zend_op_array * op_array,uint32_t op_num,uint32_t dst_num)537 static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
538 {
539 int i;
540
541 for (i = 0; i < op_array->last_try_catch; i++) {
542 if ((op_num < op_array->try_catch_array[i].finally_op ||
543 op_num >= op_array->try_catch_array[i].finally_end)
544 && (dst_num >= op_array->try_catch_array[i].finally_op &&
545 dst_num <= op_array->try_catch_array[i].finally_end)) {
546 CG(in_compilation) = 1;
547 CG(active_op_array) = op_array;
548 CG(zend_lineno) = op_array->opcodes[op_num].lineno;
549 zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
550 } else if ((op_num >= op_array->try_catch_array[i].finally_op
551 && op_num <= op_array->try_catch_array[i].finally_end)
552 && (dst_num > op_array->try_catch_array[i].finally_end
553 || dst_num < op_array->try_catch_array[i].finally_op)) {
554 CG(in_compilation) = 1;
555 CG(active_op_array) = op_array;
556 CG(zend_lineno) = op_array->opcodes[op_num].lineno;
557 zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
558 }
559 }
560 }
561
zend_get_brk_cont_target(const zend_op_array * op_array,const zend_op * opline)562 static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
563 int nest_levels = opline->op2.num;
564 int array_offset = opline->op1.num;
565 zend_brk_cont_element *jmp_to;
566 do {
567 jmp_to = &CG(context).brk_cont_array[array_offset];
568 if (nest_levels > 1) {
569 array_offset = jmp_to->parent;
570 }
571 } while (--nest_levels > 0);
572
573 return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont;
574 }
575
emit_live_range_raw(zend_op_array * op_array,uint32_t var_num,uint32_t kind,uint32_t start,uint32_t end)576 static void emit_live_range_raw(
577 zend_op_array *op_array, uint32_t var_num, uint32_t kind, uint32_t start, uint32_t end) {
578 zend_live_range *range;
579
580 op_array->last_live_range++;
581 op_array->live_range = erealloc(op_array->live_range,
582 sizeof(zend_live_range) * op_array->last_live_range);
583
584 ZEND_ASSERT(start < end);
585 range = &op_array->live_range[op_array->last_live_range - 1];
586 range->var = (uint32_t) (intptr_t) ZEND_CALL_VAR_NUM(NULL, op_array->last_var + var_num);
587 range->var |= kind;
588 range->start = start;
589 range->end = end;
590 }
591
emit_live_range(zend_op_array * op_array,uint32_t var_num,uint32_t start,uint32_t end,zend_needs_live_range_cb needs_live_range)592 static void emit_live_range(
593 zend_op_array *op_array, uint32_t var_num, uint32_t start, uint32_t end,
594 zend_needs_live_range_cb needs_live_range) {
595 zend_op *def_opline = &op_array->opcodes[start], *orig_def_opline = def_opline;
596 zend_op *use_opline = &op_array->opcodes[end];
597 uint32_t kind;
598
599 switch (def_opline->opcode) {
600 /* These should never be the first def. */
601 case ZEND_ADD_ARRAY_ELEMENT:
602 case ZEND_ADD_ARRAY_UNPACK:
603 case ZEND_ROPE_ADD:
604 ZEND_ASSERT(0);
605 return;
606 /* Result is boolean, it doesn't have to be destroyed. */
607 case ZEND_JMPZ_EX:
608 case ZEND_JMPNZ_EX:
609 case ZEND_BOOL:
610 case ZEND_BOOL_NOT:
611 /* Classes don't have to be destroyed. */
612 case ZEND_FETCH_CLASS:
613 case ZEND_DECLARE_ANON_CLASS:
614 /* FAST_CALLs don't have to be destroyed. */
615 case ZEND_FAST_CALL:
616 return;
617 case ZEND_BEGIN_SILENCE:
618 kind = ZEND_LIVE_SILENCE;
619 start++;
620 break;
621 case ZEND_ROPE_INIT:
622 kind = ZEND_LIVE_ROPE;
623 /* ROPE live ranges include the generating opcode. */
624 def_opline--;
625 break;
626 case ZEND_FE_RESET_R:
627 case ZEND_FE_RESET_RW:
628 kind = ZEND_LIVE_LOOP;
629 start++;
630 break;
631 /* Objects created via ZEND_NEW are only fully initialized
632 * after the DO_FCALL (constructor call).
633 * We are creating two live-ranges: ZEND_LINE_NEW for uninitialized
634 * part, and ZEND_LIVE_TMPVAR for initialized.
635 */
636 case ZEND_NEW:
637 {
638 int level = 0;
639 uint32_t orig_start = start;
640
641 while (def_opline + 1 < use_opline) {
642 def_opline++;
643 start++;
644 if (def_opline->opcode == ZEND_DO_FCALL) {
645 if (level == 0) {
646 break;
647 }
648 level--;
649 } else {
650 switch (def_opline->opcode) {
651 case ZEND_INIT_FCALL:
652 case ZEND_INIT_FCALL_BY_NAME:
653 case ZEND_INIT_NS_FCALL_BY_NAME:
654 case ZEND_INIT_DYNAMIC_CALL:
655 case ZEND_INIT_USER_CALL:
656 case ZEND_INIT_METHOD_CALL:
657 case ZEND_INIT_STATIC_METHOD_CALL:
658 case ZEND_NEW:
659 level++;
660 break;
661 case ZEND_DO_ICALL:
662 case ZEND_DO_UCALL:
663 case ZEND_DO_FCALL_BY_NAME:
664 level--;
665 break;
666 }
667 }
668 }
669 emit_live_range_raw(op_array, var_num, ZEND_LIVE_NEW, orig_start + 1, start + 1);
670 if (start + 1 == end) {
671 /* Trivial live-range, no need to store it. */
672 return;
673 }
674 /* break missing intentionally */
675 default:
676 start++;
677 kind = ZEND_LIVE_TMPVAR;
678
679 /* Check hook to determine whether a live range is necessary,
680 * e.g. based on type info. */
681 if (needs_live_range && !needs_live_range(op_array, orig_def_opline)) {
682 return;
683 }
684 break;
685 }
686 case ZEND_COPY_TMP:
687 {
688 /* COPY_TMP has a split live-range: One from the definition until the use in
689 * "null" branch, and another from the start of the "non-null" branch to the
690 * FREE opcode. */
691 uint32_t rt_var_num =
692 (uint32_t) (intptr_t) ZEND_CALL_VAR_NUM(NULL, op_array->last_var + var_num);
693 zend_op *block_start_op = use_opline;
694
695 if (needs_live_range && !needs_live_range(op_array, orig_def_opline)) {
696 return;
697 }
698
699 while ((block_start_op-1)->opcode == ZEND_FREE) {
700 block_start_op--;
701 }
702
703 kind = ZEND_LIVE_TMPVAR;
704 start = block_start_op - op_array->opcodes;
705 if (start != end) {
706 emit_live_range_raw(op_array, var_num, kind, start, end);
707 }
708
709 do {
710 use_opline--;
711 } while (!(
712 ((use_opline->op1_type & (IS_TMP_VAR|IS_VAR)) && use_opline->op1.var == rt_var_num) ||
713 ((use_opline->op2_type & (IS_TMP_VAR|IS_VAR)) && use_opline->op2.var == rt_var_num)
714 ));
715
716 start = def_opline + 1 - op_array->opcodes;
717 end = use_opline - op_array->opcodes;
718 emit_live_range_raw(op_array, var_num, kind, start, end);
719 return;
720 }
721 }
722
723 emit_live_range_raw(op_array, var_num, kind, start, end);
724 }
725
is_fake_def(zend_op * opline)726 static zend_bool is_fake_def(zend_op *opline) {
727 /* These opcodes only modify the result, not create it. */
728 return opline->opcode == ZEND_ROPE_ADD
729 || opline->opcode == ZEND_ADD_ARRAY_ELEMENT
730 || opline->opcode == ZEND_ADD_ARRAY_UNPACK;
731 }
732
keeps_op1_alive(zend_op * opline)733 static zend_bool keeps_op1_alive(zend_op *opline) {
734 /* These opcodes don't consume their OP1 operand,
735 * it is later freed by something else. */
736 if (opline->opcode == ZEND_CASE
737 || opline->opcode == ZEND_SWITCH_LONG
738 || opline->opcode == ZEND_FETCH_LIST_R
739 || opline->opcode == ZEND_COPY_TMP) {
740 return 1;
741 }
742 ZEND_ASSERT(opline->opcode != ZEND_SWITCH_STRING
743 && opline->opcode != ZEND_FE_FETCH_R
744 && opline->opcode != ZEND_FE_FETCH_RW
745 && opline->opcode != ZEND_FETCH_LIST_W
746 && opline->opcode != ZEND_VERIFY_RETURN_TYPE
747 && opline->opcode != ZEND_BIND_LEXICAL
748 && opline->opcode != ZEND_ROPE_ADD);
749 return 0;
750 }
751
752 /* Live ranges must be sorted by increasing start opline */
cmp_live_range(const zend_live_range * a,const zend_live_range * b)753 static int cmp_live_range(const zend_live_range *a, const zend_live_range *b) {
754 return a->start - b->start;
755 }
swap_live_range(zend_live_range * a,zend_live_range * b)756 static void swap_live_range(zend_live_range *a, zend_live_range *b) {
757 uint32_t tmp;
758 tmp = a->var;
759 a->var = b->var;
760 b->var = tmp;
761 tmp = a->start;
762 a->start = b->start;
763 b->start = tmp;
764 tmp = a->end;
765 a->end = b->end;
766 b->end = tmp;
767 }
768
zend_calc_live_ranges(zend_op_array * op_array,zend_needs_live_range_cb needs_live_range)769 static void zend_calc_live_ranges(
770 zend_op_array *op_array, zend_needs_live_range_cb needs_live_range) {
771 uint32_t opnum = op_array->last;
772 zend_op *opline = &op_array->opcodes[opnum];
773 ALLOCA_FLAG(use_heap)
774 uint32_t var_offset = op_array->last_var;
775 uint32_t *last_use = do_alloca(sizeof(uint32_t) * op_array->T, use_heap);
776 memset(last_use, -1, sizeof(uint32_t) * op_array->T);
777
778 ZEND_ASSERT(!op_array->live_range);
779 while (opnum > 0) {
780 opnum--;
781 opline--;
782
783 if ((opline->result_type & (IS_TMP_VAR|IS_VAR)) && !is_fake_def(opline)) {
784 uint32_t var_num = EX_VAR_TO_NUM(opline->result.var) - var_offset;
785 /* Defs without uses can occur for two reasons: Either because the result is
786 * genuinely unused (e.g. omitted FREE opcode for an unused boolean result), or
787 * because there are multiple defining opcodes (e.g. JMPZ_EX and QM_ASSIGN), in
788 * which case the last one starts the live range. As such, we can simply ignore
789 * missing uses here. */
790 if (EXPECTED(last_use[var_num] != (uint32_t) -1)) {
791 /* Skip trivial live-range */
792 if (opnum + 1 != last_use[var_num]) {
793 uint32_t num;
794
795 #if 1
796 /* OP_DATA uses only op1 operand */
797 ZEND_ASSERT(opline->opcode != ZEND_OP_DATA);
798 num = opnum;
799 #else
800 /* OP_DATA is really part of the previous opcode. */
801 num = opnum - (opline->opcode == ZEND_OP_DATA);
802 #endif
803 emit_live_range(op_array, var_num, num, last_use[var_num], needs_live_range);
804 }
805 last_use[var_num] = (uint32_t) -1;
806 }
807 }
808
809 if ((opline->op1_type & (IS_TMP_VAR|IS_VAR))) {
810 uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var) - var_offset;
811 if (EXPECTED(last_use[var_num] == (uint32_t) -1)) {
812 if (EXPECTED(!keeps_op1_alive(opline))) {
813 /* OP_DATA is really part of the previous opcode. */
814 last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA);
815 }
816 }
817 }
818 if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
819 uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var) - var_offset;
820 if (UNEXPECTED(opline->opcode == ZEND_FE_FETCH_R
821 || opline->opcode == ZEND_FE_FETCH_RW)) {
822 /* OP2 of FE_FETCH is actually a def, not a use. */
823 if (last_use[var_num] != (uint32_t) -1) {
824 if (opnum + 1 != last_use[var_num]) {
825 emit_live_range(
826 op_array, var_num, opnum, last_use[var_num], needs_live_range);
827 }
828 last_use[var_num] = (uint32_t) -1;
829 }
830 } else if (EXPECTED(last_use[var_num] == (uint32_t) -1)) {
831 #if 1
832 /* OP_DATA uses only op1 operand */
833 ZEND_ASSERT(opline->opcode != ZEND_OP_DATA);
834 last_use[var_num] = opnum;
835 #else
836 /* OP_DATA is really part of the previous opcode. */
837 last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA);
838 #endif
839 }
840 }
841 }
842
843 if (op_array->last_live_range > 1) {
844 zend_live_range *r1 = op_array->live_range;
845 zend_live_range *r2 = r1 + op_array->last_live_range - 1;
846
847 /* In most cases we need just revert the array */
848 while (r1 < r2) {
849 swap_live_range(r1, r2);
850 r1++;
851 r2--;
852 }
853
854 r1 = op_array->live_range;
855 r2 = r1 + op_array->last_live_range - 1;
856 while (r1 < r2) {
857 if (r1->start > (r1+1)->start) {
858 zend_sort(r1, r2 - r1 + 1, sizeof(zend_live_range),
859 (compare_func_t) cmp_live_range, (swap_func_t) swap_live_range);
860 break;
861 }
862 r1++;
863 }
864 }
865
866 free_alloca(last_use, use_heap);
867 }
868
zend_recalc_live_ranges(zend_op_array * op_array,zend_needs_live_range_cb needs_live_range)869 ZEND_API void zend_recalc_live_ranges(
870 zend_op_array *op_array, zend_needs_live_range_cb needs_live_range) {
871 /* We assume that we never create live-ranges where there were none before. */
872 ZEND_ASSERT(op_array->live_range);
873 efree(op_array->live_range);
874 op_array->live_range = NULL;
875 op_array->last_live_range = 0;
876 zend_calc_live_ranges(op_array, needs_live_range);
877 }
878
pass_two(zend_op_array * op_array)879 ZEND_API int pass_two(zend_op_array *op_array)
880 {
881 zend_op *opline, *end;
882
883 if (!ZEND_USER_CODE(op_array->type)) {
884 return 0;
885 }
886 if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT) {
887 zend_update_extended_stmts(op_array);
888 }
889 if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
890 if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_HANDLER) {
891 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array);
892 }
893 }
894
895 if (CG(context).vars_size != op_array->last_var) {
896 op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var);
897 CG(context).vars_size = op_array->last_var;
898 }
899
900 #if ZEND_USE_ABS_CONST_ADDR
901 if (CG(context).opcodes_size != op_array->last) {
902 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
903 CG(context).opcodes_size = op_array->last;
904 }
905 if (CG(context).literals_size != op_array->last_literal) {
906 op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
907 CG(context).literals_size = op_array->last_literal;
908 }
909 #else
910 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
911 ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16) +
912 sizeof(zval) * op_array->last_literal);
913 if (op_array->literals) {
914 memcpy(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16),
915 op_array->literals, sizeof(zval) * op_array->last_literal);
916 efree(op_array->literals);
917 op_array->literals = (zval*)(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16));
918 }
919 CG(context).opcodes_size = op_array->last;
920 CG(context).literals_size = op_array->last_literal;
921 #endif
922
923 /* Needs to be set directly after the opcode/literal reallocation, to ensure destruction
924 * happens correctly if any of the following fixups generate a fatal error. */
925 op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
926
927 opline = op_array->opcodes;
928 end = opline + op_array->last;
929 while (opline < end) {
930 switch (opline->opcode) {
931 case ZEND_RECV_INIT:
932 {
933 zval *val = CT_CONSTANT(opline->op2);
934 if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
935 uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
936 Z_CACHE_SLOT_P(val) = slot;
937 op_array->cache_size += sizeof(zval);
938 }
939 }
940 break;
941 case ZEND_FAST_CALL:
942 opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
943 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
944 break;
945 case ZEND_BRK:
946 case ZEND_CONT:
947 {
948 uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline);
949
950 if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
951 zend_check_finally_breakout(op_array, opline - op_array->opcodes, jmp_target);
952 }
953 opline->opcode = ZEND_JMP;
954 opline->op1.opline_num = jmp_target;
955 opline->op2.num = 0;
956 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
957 }
958 break;
959 case ZEND_GOTO:
960 zend_resolve_goto_label(op_array, opline);
961 if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
962 zend_check_finally_breakout(op_array, opline - op_array->opcodes, opline->op1.opline_num);
963 }
964 /* break omitted intentionally */
965 case ZEND_JMP:
966 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
967 break;
968 case ZEND_JMPZNZ:
969 /* absolute index to relative offset */
970 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
971 /* break omitted intentionally */
972 case ZEND_JMPZ:
973 case ZEND_JMPNZ:
974 case ZEND_JMPZ_EX:
975 case ZEND_JMPNZ_EX:
976 case ZEND_JMP_SET:
977 case ZEND_COALESCE:
978 case ZEND_FE_RESET_R:
979 case ZEND_FE_RESET_RW:
980 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
981 break;
982 case ZEND_ASSERT_CHECK:
983 {
984 /* If result of assert is unused, result of check is unused as well */
985 zend_op *call = &op_array->opcodes[opline->op2.opline_num - 1];
986 if (call->opcode == ZEND_EXT_FCALL_END) {
987 call--;
988 }
989 if (call->result_type == IS_UNUSED) {
990 opline->result_type = IS_UNUSED;
991 }
992 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
993 break;
994 }
995 case ZEND_FE_FETCH_R:
996 case ZEND_FE_FETCH_RW:
997 /* absolute index to relative offset */
998 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
999 break;
1000 case ZEND_CATCH:
1001 if (!(opline->extended_value & ZEND_LAST_CATCH)) {
1002 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1003 }
1004 break;
1005 case ZEND_RETURN:
1006 case ZEND_RETURN_BY_REF:
1007 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
1008 opline->opcode = ZEND_GENERATOR_RETURN;
1009 }
1010 break;
1011 case ZEND_SWITCH_LONG:
1012 case ZEND_SWITCH_STRING:
1013 {
1014 /* absolute indexes to relative offsets */
1015 HashTable *jumptable = Z_ARRVAL_P(CT_CONSTANT(opline->op2));
1016 zval *zv;
1017 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
1018 Z_LVAL_P(zv) = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, Z_LVAL_P(zv));
1019 } ZEND_HASH_FOREACH_END();
1020
1021 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
1022 break;
1023 }
1024 }
1025 if (opline->op1_type == IS_CONST) {
1026 ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1);
1027 } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
1028 opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op1.var);
1029 }
1030 if (opline->op2_type == IS_CONST) {
1031 ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
1032 } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
1033 opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op2.var);
1034 }
1035 if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
1036 opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->result.var);
1037 }
1038 ZEND_VM_SET_OPCODE_HANDLER(opline);
1039 opline++;
1040 }
1041
1042 zend_calc_live_ranges(op_array, NULL);
1043
1044 return 0;
1045 }
1046
get_unary_op(int opcode)1047 ZEND_API unary_op_type get_unary_op(int opcode)
1048 {
1049 switch (opcode) {
1050 case ZEND_BW_NOT:
1051 return (unary_op_type) bitwise_not_function;
1052 case ZEND_BOOL_NOT:
1053 return (unary_op_type) boolean_not_function;
1054 default:
1055 return (unary_op_type) NULL;
1056 }
1057 }
1058
get_binary_op(int opcode)1059 ZEND_API binary_op_type get_binary_op(int opcode)
1060 {
1061 switch (opcode) {
1062 case ZEND_ADD:
1063 return (binary_op_type) add_function;
1064 case ZEND_SUB:
1065 return (binary_op_type) sub_function;
1066 case ZEND_MUL:
1067 return (binary_op_type) mul_function;
1068 case ZEND_POW:
1069 return (binary_op_type) pow_function;
1070 case ZEND_DIV:
1071 return (binary_op_type) div_function;
1072 case ZEND_MOD:
1073 return (binary_op_type) mod_function;
1074 case ZEND_SL:
1075 return (binary_op_type) shift_left_function;
1076 case ZEND_SR:
1077 return (binary_op_type) shift_right_function;
1078 case ZEND_PARENTHESIZED_CONCAT:
1079 case ZEND_FAST_CONCAT:
1080 case ZEND_CONCAT:
1081 return (binary_op_type) concat_function;
1082 case ZEND_IS_IDENTICAL:
1083 return (binary_op_type) is_identical_function;
1084 case ZEND_IS_NOT_IDENTICAL:
1085 return (binary_op_type) is_not_identical_function;
1086 case ZEND_IS_EQUAL:
1087 case ZEND_CASE:
1088 return (binary_op_type) is_equal_function;
1089 case ZEND_IS_NOT_EQUAL:
1090 return (binary_op_type) is_not_equal_function;
1091 case ZEND_IS_SMALLER:
1092 return (binary_op_type) is_smaller_function;
1093 case ZEND_IS_SMALLER_OR_EQUAL:
1094 return (binary_op_type) is_smaller_or_equal_function;
1095 case ZEND_SPACESHIP:
1096 return (binary_op_type) compare_function;
1097 case ZEND_BW_OR:
1098 return (binary_op_type) bitwise_or_function;
1099 case ZEND_BW_AND:
1100 return (binary_op_type) bitwise_and_function;
1101 case ZEND_BW_XOR:
1102 return (binary_op_type) bitwise_xor_function;
1103 case ZEND_BOOL_XOR:
1104 return (binary_op_type) boolean_xor_function;
1105 default:
1106 ZEND_ASSERT(0);
1107 return (binary_op_type) NULL;
1108 }
1109 }
1110