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