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