xref: /PHP-8.3/Zend/Optimizer/zend_inference.c (revision 86ef8d54)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine, e-SSA based Type & Range Inference                      |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP 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    | https://www.php.net/license/3_01.txt                                 |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "zend_compile.h"
20 #include "zend_generators.h"
21 #include "zend_inference.h"
22 #include "zend_func_info.h"
23 #include "zend_call_graph.h"
24 #include "zend_closures.h"
25 #include "zend_worklist.h"
26 #include "zend_optimizer_internal.h"
27 
28 /* The used range inference algorithm is described in:
29  *     V. Campos, R. Rodrigues, I. de Assis Costa and F. Pereira.
30  *     "Speed and Precision in Range Analysis", SBLP'12.
31  *
32  * There are a couple degrees of freedom, we use:
33  *  * Propagation on SCCs.
34  *  * e-SSA for live range splitting.
35  *  * Only intra-procedural inference.
36  *  * Widening with warmup passes, but without jump sets.
37  */
38 
39 /* Whether to handle symbolic range constraints */
40 #define SYM_RANGE
41 
42 /* Whether to handle negative range constraints */
43 /* Negative range inference is buggy, so disabled for now */
44 #undef NEG_RANGE
45 
46 /* Number of warmup passes to use prior to widening */
47 #define RANGE_WARMUP_PASSES 16
48 
49 /* Logging for range inference in general */
50 #if 0
51 #define LOG_SSA_RANGE(...) fprintf(stderr, __VA_ARGS__)
52 #else
53 #define LOG_SSA_RANGE(...)
54 #endif
55 
56 /* Logging for negative range constraints */
57 #if 0
58 #define LOG_NEG_RANGE(...) fprintf(stderr, __VA_ARGS__)
59 #else
60 #define LOG_NEG_RANGE(...)
61 #endif
62 
63 /* Pop elements in unspecified order from worklist until it is empty */
64 #define WHILE_WORKLIST(worklist, len, i) do { \
65 	bool _done = 0; \
66 	while (!_done) { \
67 		_done = 1; \
68 		ZEND_BITSET_FOREACH(worklist, len, i) { \
69 			zend_bitset_excl(worklist, i); \
70 			_done = 0;
71 
72 #define WHILE_WORKLIST_END() \
73 		} ZEND_BITSET_FOREACH_END(); \
74 	} \
75 } while (0)
76 
77 #define CHECK_SCC_VAR(var2) \
78 	do { \
79 		if (!ssa->vars[var2].no_val) { \
80 			if (ssa->vars[var2].scc < 0) { \
81 				zend_ssa_check_scc_var(op_array, ssa, var2, index, stack); \
82 			} \
83 			if (ssa->vars[var2].scc < ssa->vars[var].scc) { \
84 				ssa->vars[var].scc = ssa->vars[var2].scc; \
85 				is_root = 0; \
86 			} \
87 		} \
88 	} while (0)
89 
90 #define CHECK_SCC_ENTRY(var2) \
91 	do { \
92 		if (ssa->vars[var2].scc != ssa->vars[var].scc) { \
93 			ssa->vars[var2].scc_entry = 1; \
94 		} \
95 	} while (0)
96 
97 #define ADD_SCC_VAR(_var) \
98 	do { \
99 		if (ssa->vars[_var].scc == scc && \
100 		    !(ssa->var_info[_var].type & MAY_BE_REF)) { \
101 			zend_bitset_incl(worklist, _var); \
102 		} \
103 	} while (0)
104 
105 #define ADD_SCC_VAR_1(_var) \
106 	do { \
107 		if (ssa->vars[_var].scc == scc && \
108 		    !(ssa->var_info[_var].type & MAY_BE_REF) && \
109 		    !zend_bitset_in(visited, _var)) { \
110 			zend_bitset_incl(worklist, _var); \
111 		} \
112 	} while (0)
113 
114 #define FOR_EACH_DEFINED_VAR(line, MACRO) \
115 	do { \
116 		if (ssa->ops[line].op1_def >= 0) { \
117 			MACRO(ssa->ops[line].op1_def); \
118 		} \
119 		if (ssa->ops[line].op2_def >= 0) { \
120 			MACRO(ssa->ops[line].op2_def); \
121 		} \
122 		if (ssa->ops[line].result_def >= 0) { \
123 			MACRO(ssa->ops[line].result_def); \
124 		} \
125 		if (op_array->opcodes[line].opcode == ZEND_OP_DATA) { \
126 			if (ssa->ops[line-1].op1_def >= 0) { \
127 				MACRO(ssa->ops[line-1].op1_def); \
128 			} \
129 			if (ssa->ops[line-1].op2_def >= 0) { \
130 				MACRO(ssa->ops[line-1].op2_def); \
131 			} \
132 			if (ssa->ops[line-1].result_def >= 0) { \
133 				MACRO(ssa->ops[line-1].result_def); \
134 			} \
135 		} else if ((uint32_t)line+1 < op_array->last && \
136 		           op_array->opcodes[line+1].opcode == ZEND_OP_DATA) { \
137 			if (ssa->ops[line+1].op1_def >= 0) { \
138 				MACRO(ssa->ops[line+1].op1_def); \
139 			} \
140 			if (ssa->ops[line+1].op2_def >= 0) { \
141 				MACRO(ssa->ops[line+1].op2_def); \
142 			} \
143 			if (ssa->ops[line+1].result_def >= 0) { \
144 				MACRO(ssa->ops[line+1].result_def); \
145 			} \
146 		} \
147 	} while (0)
148 
149 
150 #define FOR_EACH_VAR_USAGE(_var, MACRO) \
151 	do { \
152 		zend_ssa_phi *p = ssa->vars[_var].phi_use_chain; \
153 		int use = ssa->vars[_var].use_chain; \
154 		while (use >= 0) { \
155 			FOR_EACH_DEFINED_VAR(use, MACRO); \
156 			use = zend_ssa_next_use(ssa->ops, _var, use); \
157 		} \
158 		p = ssa->vars[_var].phi_use_chain; \
159 		while (p) { \
160 			MACRO(p->ssa_var); \
161 			p = zend_ssa_next_use_phi(ssa, _var, p); \
162 		} \
163 	} while (0)
164 
add_will_overflow(zend_long a,zend_long b)165 static inline bool add_will_overflow(zend_long a, zend_long b) {
166 	return (b > 0 && a > ZEND_LONG_MAX - b)
167 		|| (b < 0 && a < ZEND_LONG_MIN - b);
168 }
169 #if 0
170 static inline bool sub_will_overflow(zend_long a, zend_long b) {
171 	return (b > 0 && a < ZEND_LONG_MIN + b)
172 		|| (b < 0 && a > ZEND_LONG_MAX + b);
173 }
174 #endif
175 
176 #if 0
177 /* Recursive Pearce's SCC algorithm implementation */
178 static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, zend_worklist_stack *stack) /* {{{ */
179 {
180 	int is_root = 1;
181 #ifdef SYM_RANGE
182 	zend_ssa_phi *p;
183 #endif
184 
185 	ssa->vars[var].scc = *index;
186 	(*index)++;
187 
188 	FOR_EACH_VAR_USAGE(var, CHECK_SCC_VAR);
189 
190 #ifdef SYM_RANGE
191 	/* Process symbolic control-flow constraints */
192 	p = ssa->vars[var].sym_use_chain;
193 	while (p) {
194 		CHECK_SCC_VAR(p->ssa_var);
195 		p = p->sym_use_chain;
196 	}
197 #endif
198 
199 	if (is_root) {
200 		ssa->sccs--;
201 		while (stack->len > 0) {
202 			int var2 = zend_worklist_stack_peek(stack);
203 			if (ssa->vars[var2].scc < ssa->vars[var].scc) {
204 				break;
205 			}
206 			zend_worklist_stack_pop(stack);
207 			ssa->vars[var2].scc = ssa->sccs;
208 			(*index)--;
209 		}
210 		ssa->vars[var].scc = ssa->sccs;
211 		ssa->vars[var].scc_entry = 1;
212 		(*index)--;
213 	} else {
214 		zend_worklist_stack_push(stack, var);
215 	}
216 }
217 /* }}} */
218 
219 ZEND_API void zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
220 {
221 	int index = 0;
222 	zend_worklist_stack stack;
223 	int j;
224 	ALLOCA_FLAG(stack_use_heap)
225 
226 	ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
227 
228 	/* Find SCCs using Pearce's algorithm. */
229 	ssa->sccs = ssa->vars_count;
230 	for (j = 0; j < ssa->vars_count; j++) {
231 		if (!ssa->vars[j].no_val && ssa->vars[j].scc < 0) {
232 			zend_ssa_check_scc_var(op_array, ssa, j, &index, &stack);
233 		}
234 	}
235 
236 	if (ssa->sccs) {
237 		/* Shift SCC indexes. */
238 		for (j = 0; j < ssa->vars_count; j++) {
239 			if (ssa->vars[j].scc >= 0) {
240 				ssa->vars[j].scc -= ssa->sccs;
241 			}
242 		}
243 	}
244 	ssa->sccs = ssa->vars_count - ssa->sccs;
245 
246 	for (j = 0; j < ssa->vars_count; j++) {
247 		if (ssa->vars[j].scc >= 0) {
248 			int var = j;
249 			FOR_EACH_VAR_USAGE(var, CHECK_SCC_ENTRY);
250 		}
251 	}
252 
253 	ZEND_WORKLIST_STACK_FREE_ALLOCA(&stack, stack_use_heap);
254 }
255 /* }}} */
256 
257 #else
258 /* Iterative Pearce's SCC algorithm implementation */
259 
260 typedef struct _zend_scc_iterator {
261 	int               state;
262 	int               last;
263 	union {
264 		int           use;
265 		zend_ssa_phi *phi;
266 	};
267 } zend_scc_iterator;
268 
zend_scc_next(const zend_op_array * op_array,zend_ssa * ssa,int var,zend_scc_iterator * iterator)269 static int zend_scc_next(const zend_op_array *op_array, zend_ssa *ssa, int var, zend_scc_iterator *iterator) /* {{{ */
270 {
271 	zend_ssa_phi *phi;
272 	int use, var2;
273 
274 	switch (iterator->state) {
275 		case 0:                       goto state_0;
276 		case 1:  use = iterator->use; goto state_1;
277 		case 2:  use = iterator->use; goto state_2;
278 		case 3:  use = iterator->use; goto state_3;
279 		case 4:  use = iterator->use; goto state_4;
280 		case 5:  use = iterator->use; goto state_5;
281 		case 6:  use = iterator->use; goto state_6;
282 		case 7:  use = iterator->use; goto state_7;
283 		case 8:  use = iterator->use; goto state_8;
284 		case 9:  phi = iterator->phi; goto state_9;
285 #ifdef SYM_RANGE
286 		case 10: phi = iterator->phi; goto state_10;
287 #endif
288 		case 11:                      goto state_11;
289 	}
290 
291 state_0:
292 	use = ssa->vars[var].use_chain;
293 	while (use >= 0) {
294 		iterator->use = use;
295 		var2 = ssa->ops[use].op1_def;
296 		if (var2 >= 0 && !ssa->vars[var2].no_val) {
297 			iterator->state = 1;
298 			return var2;
299 		}
300 state_1:
301 		var2 = ssa->ops[use].op2_def;
302 		if (var2 >= 0 && !ssa->vars[var2].no_val) {
303 			iterator->state = 2;
304 			return var2;
305 		}
306 state_2:
307 		var2 = ssa->ops[use].result_def;
308 		if (var2 >= 0 && !ssa->vars[var2].no_val) {
309 			iterator->state = 3;
310 			return var2;
311 		}
312 state_3:
313 		if (op_array->opcodes[use].opcode == ZEND_OP_DATA) {
314 			var2 = ssa->ops[use-1].op1_def;
315 			if (var2 >= 0 && !ssa->vars[var2].no_val) {
316 				iterator->state = 4;
317 				return var2;
318 			}
319 state_4:
320 			var2 = ssa->ops[use-1].op2_def;
321 			if (var2 >= 0 && !ssa->vars[var2].no_val) {
322 				iterator->state = 5;
323 				return var2;
324 			}
325 state_5:
326 			var2 = ssa->ops[use-1].result_def;
327 			if (var2 >= 0 && !ssa->vars[var2].no_val) {
328 				iterator->state = 8;
329 				return var2;
330 			}
331 		} else if ((uint32_t)use+1 < op_array->last &&
332 		           op_array->opcodes[use+1].opcode == ZEND_OP_DATA) {
333 			var2 = ssa->ops[use+1].op1_def;
334 			if (var2 >= 0 && !ssa->vars[var2].no_val) {
335 				iterator->state = 6;
336 				return var2;
337 			}
338 state_6:
339 			var2 = ssa->ops[use+1].op2_def;
340 			if (var2 >= 0 && !ssa->vars[var2].no_val) {
341 				iterator->state = 7;
342 				return var2;
343 			}
344 state_7:
345 			var2 = ssa->ops[use+1].result_def;
346 			if (var2 >= 0 && !ssa->vars[var2].no_val) {
347 				iterator->state = 8;
348 				return var2;
349 			}
350 		}
351 state_8:
352 		use = zend_ssa_next_use(ssa->ops, var, use);
353 	}
354 
355 	phi = ssa->vars[var].phi_use_chain;
356 	while (phi) {
357 		var2 = phi->ssa_var;
358 		if (!ssa->vars[var2].no_val) {
359 			iterator->state = 9;
360 			iterator->phi = phi;
361 			return var2;
362 		}
363 state_9:
364 		phi = zend_ssa_next_use_phi(ssa, var, phi);
365 	}
366 
367 #ifdef SYM_RANGE
368 	/* Process symbolic control-flow constraints */
369 	phi = ssa->vars[var].sym_use_chain;
370 	while (phi) {
371 		var2 = phi->ssa_var;
372 		if (!ssa->vars[var2].no_val) {
373 			iterator->state = 10;
374 			iterator->phi = phi;
375 			return var2;
376 		}
377 state_10:
378 		phi = phi->sym_use_chain;
379 	}
380 #endif
381 
382 	iterator->state = 11;
383 state_11:
384 	return -1;
385 }
386 /* }}} */
387 
zend_ssa_check_scc_var(const zend_op_array * op_array,zend_ssa * ssa,int var,int * index,zend_worklist_stack * stack,zend_worklist_stack * vstack,zend_scc_iterator * iterators)388 static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, zend_worklist_stack *stack, zend_worklist_stack *vstack, zend_scc_iterator *iterators) /* {{{ */
389 {
390 restart:
391 	zend_worklist_stack_push(vstack, var);
392 	iterators[var].state = 0;
393 	iterators[var].last = -1;
394 	ssa->vars[var].scc_entry = 1;
395 	ssa->vars[var].scc = *index;
396 	(*index)++;
397 
398 	while (vstack->len > 0) {
399 		var = zend_worklist_stack_peek(vstack);
400 		while (1) {
401 			int var2;
402 
403 			if (iterators[var].last >= 0) {
404 				/* finish edge */
405 				var2 = iterators[var].last;
406 				if (ssa->vars[var2].scc < ssa->vars[var].scc) {
407 					ssa->vars[var].scc = ssa->vars[var2].scc;
408 					ssa->vars[var].scc_entry = 0;
409 				}
410 			}
411 			var2 = zend_scc_next(op_array, ssa, var, iterators + var);
412 			iterators[var].last = var2;
413 			if (var2 < 0) break;
414 			/* begin edge */
415 			if (ssa->vars[var2].scc < 0) {
416 				var = var2;
417 				goto restart;
418 			}
419 		}
420 
421 		/* finish visiting */
422 		zend_worklist_stack_pop(vstack);
423 		if (ssa->vars[var].scc_entry) {
424 			ssa->sccs--;
425 			while (stack->len > 0) {
426 				int var2 = zend_worklist_stack_peek(stack);
427 				if (ssa->vars[var2].scc < ssa->vars[var].scc) {
428 					break;
429 				}
430 				zend_worklist_stack_pop(stack);
431 				ssa->vars[var2].scc = ssa->sccs;
432 				(*index)--;
433 			}
434 			ssa->vars[var].scc = ssa->sccs;
435 			(*index)--;
436 		} else {
437 			zend_worklist_stack_push(stack, var);
438 		}
439 	}
440 }
441 /* }}} */
442 
zend_ssa_find_sccs(const zend_op_array * op_array,zend_ssa * ssa)443 ZEND_API void zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
444 {
445 	int index = 0;
446 	zend_worklist_stack stack, vstack;
447 	zend_scc_iterator *iterators;
448 	int j;
449 	ALLOCA_FLAG(stack_use_heap)
450 	ALLOCA_FLAG(vstack_use_heap)
451 	ALLOCA_FLAG(iterators_use_heap)
452 
453 	iterators = do_alloca(sizeof(zend_scc_iterator) * ssa->vars_count, iterators_use_heap);
454 	ZEND_WORKLIST_STACK_ALLOCA(&vstack, ssa->vars_count, vstack_use_heap);
455 	ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
456 
457 	/* Find SCCs using Pearce's algorithm. */
458 	ssa->sccs = ssa->vars_count;
459 	for (j = 0; j < ssa->vars_count; j++) {
460 		if (!ssa->vars[j].no_val && ssa->vars[j].scc < 0) {
461 			zend_ssa_check_scc_var(op_array, ssa, j, &index, &stack, &vstack, iterators);
462 		}
463 	}
464 
465 	if (ssa->sccs) {
466 		/* Shift SCC indexes. */
467 		for (j = 0; j < ssa->vars_count; j++) {
468 			if (ssa->vars[j].scc >= 0) {
469 				ssa->vars[j].scc -= ssa->sccs;
470 			}
471 		}
472 	}
473 	ssa->sccs = ssa->vars_count - ssa->sccs;
474 
475 	for (j = 0; j < ssa->vars_count; j++) {
476 		if (ssa->vars[j].scc >= 0) {
477 			int var = j;
478 			FOR_EACH_VAR_USAGE(var, CHECK_SCC_ENTRY);
479 		}
480 	}
481 
482 	ZEND_WORKLIST_STACK_FREE_ALLOCA(&stack, stack_use_heap);
483 	ZEND_WORKLIST_STACK_FREE_ALLOCA(&vstack, vstack_use_heap);
484 	free_alloca(iterators, iterators_use_heap);
485 }
486 /* }}} */
487 
488 #endif
489 
zend_ssa_find_false_dependencies(const zend_op_array * op_array,zend_ssa * ssa)490 ZEND_API void zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
491 {
492 	zend_ssa_var *ssa_vars = ssa->vars;
493 	zend_ssa_op *ssa_ops = ssa->ops;
494 	int ssa_vars_count = ssa->vars_count;
495 	zend_bitset worklist;
496 	int i, j, use;
497 	zend_ssa_phi *p;
498 	ALLOCA_FLAG(use_heap);
499 
500 	if (!op_array->function_name || !ssa->vars || !ssa->ops) {
501 		return;
502 	}
503 
504 	worklist = do_alloca(sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count), use_heap);
505 	memset(worklist, 0, sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count));
506 
507 	for (i = 0; i < ssa_vars_count; i++) {
508 		ssa_vars[i].no_val = 1; /* mark as unused */
509 		use = ssa->vars[i].use_chain;
510 		while (use >= 0) {
511 			if (!zend_ssa_is_no_val_use(&op_array->opcodes[use], &ssa->ops[use], i)) {
512 				ssa_vars[i].no_val = 0; /* used directly */
513 				zend_bitset_incl(worklist, i);
514 				break;
515 			}
516 			use = zend_ssa_next_use(ssa_ops, i, use);
517 		}
518 	}
519 
520 	WHILE_WORKLIST(worklist, zend_bitset_len(ssa_vars_count), i) {
521 		if (ssa_vars[i].definition_phi) {
522 			/* mark all possible sources as used */
523 			p = ssa_vars[i].definition_phi;
524 			if (p->pi >= 0) {
525 				if (ssa_vars[p->sources[0]].no_val) {
526 					ssa_vars[p->sources[0]].no_val = 0; /* used indirectly */
527 					zend_bitset_incl(worklist, p->sources[0]);
528 				}
529 			} else {
530 				for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
531 					ZEND_ASSERT(p->sources[j] >= 0);
532 					if (ssa->vars[p->sources[j]].no_val) {
533 						ssa_vars[p->sources[j]].no_val = 0; /* used indirectly */
534 						zend_bitset_incl(worklist, p->sources[j]);
535 					}
536 				}
537 			}
538 		}
539 	} WHILE_WORKLIST_END();
540 
541 	free_alloca(worklist, use_heap);
542 }
543 /* }}} */
544 
545 /* From "Hacker's Delight" */
minOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)546 zend_ulong minOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
547 {
548 	zend_ulong m, temp;
549 
550 	m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
551 	while (m != 0) {
552 		if (~a & c & m) {
553 			temp = (a | m) & -m;
554 			if (temp <= b) {
555 				a = temp;
556 				break;
557 			}
558 		} else if (a & ~c & m) {
559 			temp = (c | m) & -m;
560 			if (temp <= d) {
561 				c = temp;
562 				break;
563 			}
564 		}
565 		m = m >> 1;
566 	}
567 	return a | c;
568 }
569 
maxOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)570 zend_ulong maxOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
571 {
572 	zend_ulong m, temp;
573 
574 	m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
575 	while (m != 0) {
576 		if (b & d & m) {
577 			temp = (b - m) | (m - 1);
578 			if (temp >= a) {
579 				b = temp;
580 				break;
581 			}
582 			temp = (d - m) | (m - 1);
583 			if (temp >= c) {
584 				d = temp;
585 				break;
586 			}
587 		}
588 		m = m >> 1;
589 	}
590 	return b | d;
591 }
592 
minAND(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)593 zend_ulong minAND(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
594 {
595 	zend_ulong m, temp;
596 
597 	m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
598 	while (m != 0) {
599 		if (~a & ~c & m) {
600 			temp = (a | m) & -m;
601 			if (temp <= b) {
602 				a = temp;
603 				break;
604 			}
605 			temp = (c | m) & -m;
606 			if (temp <= d) {
607 				c = temp;
608 				break;
609 			}
610 		}
611 		m = m >> 1;
612 	}
613 	return a & c;
614 }
615 
maxAND(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)616 zend_ulong maxAND(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
617 {
618 	zend_ulong m, temp;
619 
620 	m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
621 	while (m != 0) {
622 		if (b & ~d & m) {
623 			temp = (b | ~m) | (m - 1);
624 			if (temp >= a) {
625 				b = temp;
626 				break;
627 			}
628 		} else if (~b & d & m) {
629 			temp = (d | ~m) | (m - 1);
630 			if (temp >= c) {
631 				d = temp;
632 				break;
633 			}
634 		}
635 		m = m >> 1;
636 	}
637 	return b & d;
638 }
639 
minXOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)640 zend_ulong minXOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
641 {
642 	return minAND(a, b, ~d, ~c) | minAND(~b, ~a, c, d);
643 }
644 
maxXOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)645 zend_ulong maxXOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
646 {
647 	return maxOR(0, maxAND(a, b, ~d, ~c), 0, maxAND(~b, ~a, c, d));
648 }
649 
650 /* Based on "Hacker's Delight" */
651 
652 /*
653 0: + + + + 0 0 0 0 => 0 0 + min/max
654 2: + + - + 0 0 1 0 => 1 0 ? min(a,b,c,-1)/max(a,b,0,d)
655 3: + + - - 0 0 1 1 => 1 1 - min/max
656 8: - + + + 1 0 0 0 => 1 0 ? min(a,-1,b,d)/max(0,b,c,d)
657 a: - + - + 1 0 1 0 => 1 0 ? MIN(a,c)/max(0,b,0,d)
658 b: - + - - 1 0 1 1 => 1 1 - c/-1
659 c: - - + + 1 1 0 0 => 1 1 - min/max
660 e: - - - + 1 1 1 0 => 1 1 - a/-1
661 f  - - - - 1 1 1 1 => 1 1 - min/max
662 */
zend_ssa_range_or(zend_long a,zend_long b,zend_long c,zend_long d,zend_ssa_range * tmp)663 static void zend_ssa_range_or(zend_long a, zend_long b, zend_long c, zend_long d, zend_ssa_range *tmp)
664 {
665 	int x = ((a < 0) ? 8 : 0) |
666 	        ((b < 0) ? 4 : 0) |
667 	        ((c < 0) ? 2 : 0) |
668 	        ((d < 0) ? 1 : 0);
669 	switch (x) {
670 		case 0x0:
671 		case 0x3:
672 		case 0xc:
673 		case 0xf:
674 			tmp->min = minOR(a, b, c, d);
675 			tmp->max = maxOR(a, b, c, d);
676 			break;
677 		case 0x2:
678 			tmp->min = minOR(a, b, c, -1);
679 			tmp->max = maxOR(a, b, 0, d);
680 			break;
681 		case 0x8:
682 			tmp->min = minOR(a, -1, c, d);
683 			tmp->max = maxOR(0, b, c, d);
684 			break;
685 		case 0xa:
686 			tmp->min = MIN(a, c);
687 			tmp->max = maxOR(0, b, 0, d);
688 			break;
689 		case 0xb:
690 			tmp->min = c;
691 			tmp->max = -1;
692 			break;
693 		case 0xe:
694 			tmp->min = a;
695 			tmp->max = -1;
696 			break;
697 	}
698 }
699 
700 /*
701 0: + + + + 0 0 0 0 => 0 0 + min/max
702 2: + + - + 0 0 1 0 => 0 0 + 0/b
703 3: + + - - 0 0 1 1 => 0 0 + min/max
704 8: - + + + 1 0 0 0 => 0 0 + 0/d
705 a: - + - + 1 0 1 0 => 1 0 ? min(a,-1,c,-1)/NAX(b,d)
706 b: - + - - 1 0 1 1 => 1 0 ? min(a,-1,c,d)/max(0,b,c,d)
707 c: - - + + 1 1 0 0 => 1 1 - min/max
708 e: - - - + 1 1 1 0 => 1 0 ? min(a,b,c,-1)/max(a,b,0,d)
709 f  - - - - 1 1 1 1 => 1 1 - min/max
710 */
zend_ssa_range_and(zend_long a,zend_long b,zend_long c,zend_long d,zend_ssa_range * tmp)711 static void zend_ssa_range_and(zend_long a, zend_long b, zend_long c, zend_long d, zend_ssa_range *tmp)
712 {
713 	int x = ((a < 0) ? 8 : 0) |
714 	        ((b < 0) ? 4 : 0) |
715 	        ((c < 0) ? 2 : 0) |
716 	        ((d < 0) ? 1 : 0);
717 	switch (x) {
718 		case 0x0:
719 		case 0x3:
720 		case 0xc:
721 		case 0xf:
722 			tmp->min = minAND(a, b, c, d);
723 			tmp->max = maxAND(a, b, c, d);
724 			break;
725 		case 0x2:
726 			tmp->min = 0;
727 			tmp->max = b;
728 			break;
729 		case 0x8:
730 			tmp->min = 0;
731 			tmp->max = d;
732 			break;
733 		case 0xa:
734 			tmp->min = minAND(a, -1, c, -1);
735 			tmp->max = MAX(b, d);
736 			break;
737 		case 0xb:
738 			tmp->min = minAND(a, -1, c, d);
739 			tmp->max = maxAND(0, b, c, d);
740 			break;
741 		case 0xe:
742 			tmp->min = minAND(a, b, c, -1);
743 			tmp->max = maxAND(a, b, 0, d);
744 			break;
745 	}
746 }
747 
zend_abs_range(zend_long min,zend_long max,zend_long * abs_min,zend_long * abs_max)748 static inline bool zend_abs_range(
749 		zend_long min, zend_long max, zend_long *abs_min, zend_long *abs_max) {
750 	if (min == ZEND_LONG_MIN) {
751 		/* Cannot take absolute value of LONG_MIN  */
752 		return 0;
753 	}
754 
755 	if (min >= 0) {
756 		*abs_min = min;
757 		*abs_max = max;
758 	} else if (max <= 0) {
759 		*abs_min = -max;
760 		*abs_max = -min;
761 	} else {
762 		/* Range crossing zero */
763 		*abs_min = 0;
764 		*abs_max = MAX(max, -min);
765 	}
766 
767 	return 1;
768 }
769 
safe_shift_left(zend_long n,zend_long s)770 static inline zend_long safe_shift_left(zend_long n, zend_long s) {
771 	return (zend_long) ((zend_ulong) n << (zend_ulong) s);
772 }
773 
shift_left_overflows(zend_long n,zend_long s)774 static inline bool shift_left_overflows(zend_long n, zend_long s) {
775 	/* This considers shifts that shift in the sign bit to be overflowing as well */
776 	if (n >= 0) {
777 		return s >= SIZEOF_ZEND_LONG * 8 - 1 || safe_shift_left(n, s) < n;
778 	} else {
779 		return s >= SIZEOF_ZEND_LONG * 8 || safe_shift_left(n, s) > n;
780 	}
781 }
782 
783 /* If b does not divide a exactly, return the two adjacent values between which the real result
784  * lies. */
float_div(zend_long a,zend_long b,zend_long * r1,zend_long * r2)785 static void float_div(zend_long a, zend_long b, zend_long *r1, zend_long *r2) {
786 	*r1 = *r2 = a / b;
787 	if (a % b != 0) {
788 		if (*r2 < 0) {
789 			(*r2)--;
790 		} else {
791 			(*r2)++;
792 		}
793 	}
794 }
795 
zend_inference_calc_binary_op_range(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op * opline,const zend_ssa_op * ssa_op,uint8_t opcode,zend_ssa_range * tmp)796 static bool zend_inference_calc_binary_op_range(
797 		const zend_op_array *op_array, const zend_ssa *ssa,
798 		const zend_op *opline, const zend_ssa_op *ssa_op, uint8_t opcode, zend_ssa_range *tmp) {
799 	zend_long op1_min, op2_min, op1_max, op2_max, t1, t2, t3, t4;
800 
801 	switch (opcode) {
802 		case ZEND_ADD:
803 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
804 				op1_min = OP1_MIN_RANGE();
805 				op2_min = OP2_MIN_RANGE();
806 				op1_max = OP1_MAX_RANGE();
807 				op2_max = OP2_MAX_RANGE();
808 				if (OP1_RANGE_UNDERFLOW() ||
809 					OP2_RANGE_UNDERFLOW() ||
810 					zend_add_will_overflow(op1_min, op2_min)) {
811 					tmp->underflow = 1;
812 					tmp->min = ZEND_LONG_MIN;
813 				} else {
814 					tmp->min = op1_min + op2_min;
815 				}
816 				if (OP1_RANGE_OVERFLOW() ||
817 					OP2_RANGE_OVERFLOW() ||
818 					zend_add_will_overflow(op1_max, op2_max)) {
819 					tmp->overflow = 1;
820 					tmp->max = ZEND_LONG_MAX;
821 				} else {
822 					tmp->max = op1_max + op2_max;
823 				}
824 				return 1;
825 			}
826 			break;
827 		case ZEND_SUB:
828 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
829 				op1_min = OP1_MIN_RANGE();
830 				op2_min = OP2_MIN_RANGE();
831 				op1_max = OP1_MAX_RANGE();
832 				op2_max = OP2_MAX_RANGE();
833 				if (OP1_RANGE_UNDERFLOW() ||
834 					OP2_RANGE_OVERFLOW() ||
835 					zend_sub_will_overflow(op1_min, op2_max)) {
836 					tmp->underflow = 1;
837 					tmp->min = ZEND_LONG_MIN;
838 				} else {
839 					tmp->min = op1_min - op2_max;
840 				}
841 				if (OP1_RANGE_OVERFLOW() ||
842 					OP2_RANGE_UNDERFLOW() ||
843 					zend_sub_will_overflow(op1_max, op2_min)) {
844 					tmp->overflow = 1;
845 					tmp->max = ZEND_LONG_MAX;
846 				} else {
847 					tmp->max = op1_max - op2_min;
848 				}
849 				return 1;
850 			}
851 			break;
852 		case ZEND_MUL:
853 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
854 				double dummy;
855 				zend_long t1_overflow, t2_overflow, t3_overflow, t4_overflow;
856 				op1_min = OP1_MIN_RANGE();
857 				op2_min = OP2_MIN_RANGE();
858 				op1_max = OP1_MAX_RANGE();
859 				op2_max = OP2_MAX_RANGE();
860 				/* Suppress uninit variable warnings, these will only be used if the overflow
861 				 * flags are all false. */
862 				t1 = t2 = t3 = t4 = 0;
863 				ZEND_SIGNED_MULTIPLY_LONG(op1_min, op2_min, t1, dummy, t1_overflow);
864 				ZEND_SIGNED_MULTIPLY_LONG(op1_min, op2_max, t2, dummy, t2_overflow);
865 				ZEND_SIGNED_MULTIPLY_LONG(op1_max, op2_min, t3, dummy, t3_overflow);
866 				ZEND_SIGNED_MULTIPLY_LONG(op1_max, op2_max, t4, dummy, t4_overflow);
867 				(void) dummy;
868 
869 				// FIXME: more careful overflow checks?
870 				if (OP1_RANGE_UNDERFLOW() || OP2_RANGE_UNDERFLOW() ||
871 					OP1_RANGE_OVERFLOW() || OP2_RANGE_OVERFLOW()  ||
872 					t1_overflow || t2_overflow || t3_overflow || t4_overflow
873 				) {
874 					tmp->underflow = 1;
875 					tmp->overflow = 1;
876 					tmp->min = ZEND_LONG_MIN;
877 					tmp->max = ZEND_LONG_MAX;
878 				} else {
879 					tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
880 					tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
881 				}
882 				return 1;
883 			}
884 			break;
885 		case ZEND_DIV:
886 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
887 				op1_min = OP1_MIN_RANGE();
888 				op2_min = OP2_MIN_RANGE();
889 				op1_max = OP1_MAX_RANGE();
890 				op2_max = OP2_MAX_RANGE();
891 
892 				/* If op2 crosses zero, then floating point values close to zero might be
893 				 * possible, which will result in arbitrarily large results (overflow). Also
894 				 * avoid dividing LONG_MIN by -1, which is UB. */
895 				if (OP1_RANGE_UNDERFLOW() || OP2_RANGE_UNDERFLOW() ||
896 					OP1_RANGE_OVERFLOW() || OP2_RANGE_OVERFLOW() ||
897 					(op2_min <= 0 && op2_max >= 0) ||
898 					(op1_min == ZEND_LONG_MIN && op2_max == -1)
899 				) {
900 					tmp->underflow = 1;
901 					tmp->overflow = 1;
902 					tmp->min = ZEND_LONG_MIN;
903 					tmp->max = ZEND_LONG_MAX;
904 				} else {
905 					zend_long t1_, t2_, t3_, t4_;
906 					float_div(op1_min, op2_min, &t1, &t1_);
907 					float_div(op1_min, op2_max, &t2, &t2_);
908 					float_div(op1_max, op2_min, &t3, &t3_);
909 					float_div(op1_max, op2_max, &t4, &t4_);
910 
911 					tmp->min = MIN(MIN(MIN(t1, t2), MIN(t3, t4)), MIN(MIN(t1_, t2_), MIN(t3_, t4_)));
912 					tmp->max = MAX(MAX(MAX(t1, t2), MAX(t3, t4)), MAX(MAX(t1_, t2_), MAX(t3_, t4_)));
913 				}
914 				return 1;
915 			}
916 			break;
917 		case ZEND_MOD:
918 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
919 				if (OP1_RANGE_UNDERFLOW() ||
920 					OP2_RANGE_UNDERFLOW() ||
921 					OP1_RANGE_OVERFLOW()  ||
922 					OP2_RANGE_OVERFLOW()) {
923 					tmp->min = ZEND_LONG_MIN;
924 					tmp->max = ZEND_LONG_MAX;
925 				} else {
926 					zend_long op2_abs_min, op2_abs_max;
927 
928 					op1_min = OP1_MIN_RANGE();
929 					op2_min = OP2_MIN_RANGE();
930 					op1_max = OP1_MAX_RANGE();
931 					op2_max = OP2_MAX_RANGE();
932 					if (!zend_abs_range(op2_min, op2_max, &op2_abs_min, &op2_abs_max)) {
933 						break;
934 					}
935 
936 					if (op2_abs_max == 0) {
937 						/* Always modulus by zero, nothing we can do */
938 						break;
939 					}
940 					if (op2_abs_min == 0) {
941 						/* Ignore the modulus by zero case, which will throw */
942 						op2_abs_min++;
943 					}
944 
945 					if (op1_min >= 0) {
946 						tmp->min = op1_max < op2_abs_min ? op1_min : 0;
947 						tmp->max = MIN(op1_max, op2_abs_max - 1);
948 					} else if (op1_max <= 0) {
949 						tmp->min = MAX(op1_min, -op2_abs_max + 1);
950 						tmp->max = op1_min > -op2_abs_min ? op1_max : 0;
951 					} else {
952 						tmp->min = MAX(op1_min, -op2_abs_max + 1);
953 						tmp->max = MIN(op1_max, op2_abs_max - 1);
954 					}
955 				}
956 				return 1;
957 			}
958 			break;
959 		case ZEND_SL:
960 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
961 				if (OP1_RANGE_UNDERFLOW() ||
962 					OP2_RANGE_UNDERFLOW() ||
963 					OP1_RANGE_OVERFLOW() ||
964 					OP2_RANGE_OVERFLOW()) {
965 					tmp->min = ZEND_LONG_MIN;
966 					tmp->max = ZEND_LONG_MAX;
967 				} else {
968 					op1_min = OP1_MIN_RANGE();
969 					op2_min = OP2_MIN_RANGE();
970 					op1_max = OP1_MAX_RANGE();
971 					op2_max = OP2_MAX_RANGE();
972 
973 					/* Shifts by negative numbers will throw, ignore them */
974 					if (op2_min < 0) {
975 						op2_min = 0;
976 					}
977 					if (op2_max < 0) {
978 						op2_max = 0;
979 					}
980 
981 					if (shift_left_overflows(op1_min, op2_max)
982 							|| shift_left_overflows(op1_max, op2_max)) {
983 						tmp->min = ZEND_LONG_MIN;
984 						tmp->max = ZEND_LONG_MAX;
985 					} else {
986 						t1 = safe_shift_left(op1_min, op2_min);
987 						t2 = safe_shift_left(op1_min, op2_max);
988 						t3 = safe_shift_left(op1_max, op2_min);
989 						t4 = safe_shift_left(op1_max, op2_max);
990 						tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
991 						tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
992 					}
993 				}
994 				return 1;
995 			}
996 			break;
997 		case ZEND_SR:
998 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
999 				if (OP1_RANGE_UNDERFLOW() ||
1000 					OP2_RANGE_UNDERFLOW() ||
1001 					OP1_RANGE_OVERFLOW() ||
1002 					OP2_RANGE_OVERFLOW()) {
1003 					tmp->min = ZEND_LONG_MIN;
1004 					tmp->max = ZEND_LONG_MAX;
1005 				} else {
1006 					op1_min = OP1_MIN_RANGE();
1007 					op2_min = OP2_MIN_RANGE();
1008 					op1_max = OP1_MAX_RANGE();
1009 					op2_max = OP2_MAX_RANGE();
1010 
1011 					/* Shifts by negative numbers will throw, ignore them */
1012 					if (op2_min < 0) {
1013 						op2_min = 0;
1014 					}
1015 					if (op2_max < 0) {
1016 						op2_max = 0;
1017 					}
1018 
1019 					/* Shifts by more than the integer size will be 0 or -1 */
1020 					if (op2_min >= SIZEOF_ZEND_LONG * 8) {
1021 						op2_min = SIZEOF_ZEND_LONG * 8 - 1;
1022 					}
1023 					if (op2_max >= SIZEOF_ZEND_LONG * 8) {
1024 						op2_max = SIZEOF_ZEND_LONG * 8 - 1;
1025 					}
1026 
1027 					t1 = op1_min >> op2_min;
1028 					t2 = op1_min >> op2_max;
1029 					t3 = op1_max >> op2_min;
1030 					t4 = op1_max >> op2_max;
1031 					tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
1032 					tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
1033 				}
1034 				return 1;
1035 			}
1036 			break;
1037 		case ZEND_BW_OR:
1038 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
1039 				if (OP1_RANGE_UNDERFLOW() ||
1040 					OP2_RANGE_UNDERFLOW() ||
1041 					OP1_RANGE_OVERFLOW() ||
1042 					OP2_RANGE_OVERFLOW()) {
1043 					tmp->min = ZEND_LONG_MIN;
1044 					tmp->max = ZEND_LONG_MAX;
1045 				} else {
1046 					op1_min = OP1_MIN_RANGE();
1047 					op2_min = OP2_MIN_RANGE();
1048 					op1_max = OP1_MAX_RANGE();
1049 					op2_max = OP2_MAX_RANGE();
1050 					zend_ssa_range_or(op1_min, op1_max, op2_min, op2_max, tmp);
1051 				}
1052 				return 1;
1053 			}
1054 			break;
1055 		case ZEND_BW_AND:
1056 			if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
1057 				if (OP1_RANGE_UNDERFLOW() ||
1058 					OP2_RANGE_UNDERFLOW() ||
1059 					OP1_RANGE_OVERFLOW() ||
1060 					OP2_RANGE_OVERFLOW()) {
1061 					tmp->min = ZEND_LONG_MIN;
1062 					tmp->max = ZEND_LONG_MAX;
1063 				} else {
1064 					op1_min = OP1_MIN_RANGE();
1065 					op2_min = OP2_MIN_RANGE();
1066 					op1_max = OP1_MAX_RANGE();
1067 					op2_max = OP2_MAX_RANGE();
1068 					zend_ssa_range_and(op1_min, op1_max, op2_min, op2_max, tmp);
1069 				}
1070 				return 1;
1071 			}
1072 			break;
1073 		case ZEND_BW_XOR:
1074 			// TODO
1075 			break;
1076 		EMPTY_SWITCH_DEFAULT_CASE()
1077 	}
1078 	return 0;
1079 }
1080 
zend_inference_calc_range(const zend_op_array * op_array,const zend_ssa * ssa,int var,int widening,int narrowing,zend_ssa_range * tmp)1081 static bool zend_inference_calc_range(const zend_op_array *op_array, const zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp)
1082 {
1083 	uint32_t line;
1084 	const zend_op *opline;
1085 	const zend_ssa_op *ssa_op;
1086 
1087 	if (ssa->vars[var].definition_phi) {
1088 		const zend_ssa_phi *p = ssa->vars[var].definition_phi;
1089 		int i;
1090 
1091 		tmp->underflow = 0;
1092 		tmp->min = ZEND_LONG_MAX;
1093 		tmp->max = ZEND_LONG_MIN;
1094 		tmp->overflow = 0;
1095 		if (p->pi >= 0 && p->has_range_constraint) {
1096 			const zend_ssa_range_constraint *constraint = &p->constraint.range;
1097 			if (constraint->negative) {
1098 				int src1 = p->sources[0];
1099 
1100 				if (ssa->var_info[src1].has_range) {
1101 					*tmp = ssa->var_info[src1].range;
1102 					if (constraint->range.min == constraint->range.max
1103 					 && !constraint->range.underflow
1104 					 && !constraint->range.overflow
1105 					 && p->constraint.range.min_ssa_var < 0
1106 					 && p->constraint.range.max_ssa_var < 0
1107 					 && ssa->vars[src1].definition >= 0) {
1108 						/* Check for constrained induction variable */
1109 						line = ssa->vars[src1].definition;
1110 						opline = op_array->opcodes + line;
1111 						switch (opline->opcode) {
1112 							case ZEND_PRE_DEC:
1113 							case ZEND_POST_DEC:
1114 								if (!tmp->underflow) {
1115 									const zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi;
1116 
1117 									if (p && p->pi < 0
1118 									 && ssa->cfg.blocks[p->block].predecessors_count == 2
1119 									 && p->sources[1] == var
1120 									 && ssa->var_info[p->sources[0]].has_range
1121 									 && ssa->var_info[p->sources[0]].range.min > constraint->range.max) {
1122 										tmp->min = constraint->range.max + 1;
1123 									}
1124 								}
1125 								break;
1126 							case ZEND_PRE_INC:
1127 							case ZEND_POST_INC:
1128 								if (!tmp->overflow) {
1129 									const zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi;
1130 
1131 									if (p && p->pi < 0
1132 									 && ssa->cfg.blocks[p->block].predecessors_count == 2
1133 									 && p->sources[1] == var
1134 									 && ssa->var_info[p->sources[0]].has_range
1135 									 && ssa->var_info[p->sources[0]].range.max < constraint->range.min) {
1136 										tmp->max = constraint->range.min - 1;
1137 									}
1138 								}
1139 								break;
1140 						}
1141 					}
1142 				} else if (narrowing) {
1143 					tmp->underflow = 1;
1144 					tmp->min = ZEND_LONG_MIN;
1145 					tmp->max = ZEND_LONG_MAX;
1146 					tmp->overflow = 1;
1147 				}
1148 
1149 #ifdef NEG_RANGE
1150 				if (constraint->min_ssa_var < 0 &&
1151 				    constraint->max_ssa_var < 0 &&
1152 				    ssa->var_info[p->ssa_var].has_range) {
1153 					LOG_NEG_RANGE("%s() #%d [%ld..%ld] -> [%ld..%ld]?\n",
1154 						ZSTR_VAL(op_array->function_name),
1155 						p->ssa_var,
1156 						ssa->var_info[p->ssa_var].range.min,
1157 						ssa->var_info[p->ssa_var].range.max,
1158 						tmp->min,
1159 						tmp->max);
1160 					if (constraint->negative == NEG_USE_LT &&
1161 					    tmp->max >= constraint->range.min) {
1162 						tmp->overflow = 0;
1163 						tmp->max = constraint->range.min - 1;
1164 						LOG_NEG_RANGE("  => [%ld..%ld]\n", tmp->min, tmp->max);
1165 					} else if (constraint->negative == NEG_USE_GT &&
1166 					           tmp->min <= constraint->range.max) {
1167 						tmp->underflow = 0;
1168 						tmp->min = constraint->range.max + 1;
1169 						LOG_NEG_RANGE("  => [%ld..%ld]\n", tmp->min, tmp->max);
1170 					}
1171 				}
1172 #endif
1173 			} else if (ssa->var_info[p->sources[0]].has_range) {
1174 				/* intersection */
1175 				*tmp = ssa->var_info[p->sources[0]].range;
1176 				if (constraint->min_ssa_var < 0) {
1177 					tmp->underflow = constraint->range.underflow && tmp->underflow;
1178 					tmp->min = MAX(constraint->range.min, tmp->min);
1179 #ifdef SYM_RANGE
1180 				} else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) {
1181 					tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow && tmp->underflow;
1182 					if (!add_will_overflow(ssa->var_info[constraint->min_ssa_var].range.min, constraint->range.min)) {
1183 						tmp->min = MAX(ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min, tmp->min);
1184 					}
1185 #endif
1186 				}
1187 				if (constraint->max_ssa_var < 0) {
1188 					tmp->max = MIN(constraint->range.max, tmp->max);
1189 					tmp->overflow = constraint->range.overflow && tmp->overflow;
1190 #ifdef SYM_RANGE
1191 				} else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) {
1192 					if (!add_will_overflow(ssa->var_info[constraint->max_ssa_var].range.max, constraint->range.max)) {
1193 						tmp->max = MIN(ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max, tmp->max);
1194 					}
1195 					tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow && tmp->overflow;
1196 #endif
1197 				}
1198 			} else if (narrowing) {
1199 				if (constraint->min_ssa_var < 0) {
1200 					tmp->underflow = constraint->range.underflow;
1201 					tmp->min = constraint->range.min;
1202 #ifdef SYM_RANGE
1203 				} else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) {
1204 					if (add_will_overflow(ssa->var_info[constraint->min_ssa_var].range.min, constraint->range.min)) {
1205 						tmp->underflow = 1;
1206 						tmp->min = ZEND_LONG_MIN;
1207 					} else {
1208 						tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow;
1209 						tmp->min = ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min;
1210 					}
1211 #endif
1212 				} else {
1213 					tmp->underflow = 1;
1214 					tmp->min = ZEND_LONG_MIN;
1215 				}
1216 				if (constraint->max_ssa_var < 0) {
1217 					tmp->max = constraint->range.max;
1218 					tmp->overflow = constraint->range.overflow;
1219 #ifdef SYM_RANGE
1220 				} else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) {
1221 					if (add_will_overflow(ssa->var_info[constraint->max_ssa_var].range.max, constraint->range.max)) {
1222 						tmp->overflow = 1;
1223 						tmp->max = ZEND_LONG_MAX;
1224 					} else {
1225 						tmp->max = ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max;
1226 						tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow;
1227 					}
1228 #endif
1229 				} else {
1230 					tmp->max = ZEND_LONG_MAX;
1231 					tmp->overflow = 1;
1232 				}
1233 			}
1234 		} else {
1235 			for (i = 0; i < ssa->cfg.blocks[p->block].predecessors_count; i++) {
1236 				ZEND_ASSERT(p->sources[i] >= 0);
1237 				if (ssa->var_info[p->sources[i]].has_range) {
1238 					/* union */
1239 					tmp->underflow |= ssa->var_info[p->sources[i]].range.underflow;
1240 					tmp->min = MIN(tmp->min, ssa->var_info[p->sources[i]].range.min);
1241 					tmp->max = MAX(tmp->max, ssa->var_info[p->sources[i]].range.max);
1242 					tmp->overflow |= ssa->var_info[p->sources[i]].range.overflow;
1243 				} else if (narrowing) {
1244 					tmp->underflow = 1;
1245 					tmp->min = ZEND_LONG_MIN;
1246 					tmp->max = ZEND_LONG_MAX;
1247 					tmp->overflow = 1;
1248 				}
1249 			}
1250 		}
1251 		return (tmp->min <= tmp->max);
1252 	} else if (ssa->vars[var].definition < 0) {
1253 		return 0;
1254 	}
1255 	line = ssa->vars[var].definition;
1256 	opline = op_array->opcodes + line;
1257 	ssa_op = &ssa->ops[line];
1258 
1259 	return zend_inference_propagate_range(op_array, ssa, opline, ssa_op, var, tmp);
1260 }
1261 
zend_inference_propagate_range(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op * opline,const zend_ssa_op * ssa_op,int var,zend_ssa_range * tmp)1262 ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp)
1263 {
1264 	tmp->underflow = 0;
1265 	tmp->overflow = 0;
1266 	switch (opline->opcode) {
1267 		case ZEND_ADD:
1268 		case ZEND_SUB:
1269 		case ZEND_MUL:
1270 		case ZEND_DIV:
1271 		case ZEND_MOD:
1272 		case ZEND_SL:
1273 		case ZEND_SR:
1274 		case ZEND_BW_OR:
1275 		case ZEND_BW_AND:
1276 		case ZEND_BW_XOR:
1277 			if (ssa_op->result_def == var) {
1278 				return zend_inference_calc_binary_op_range(
1279 					op_array, ssa, opline, ssa_op, opline->opcode, tmp);
1280 			}
1281 			break;
1282 
1283 		case ZEND_BW_NOT:
1284 			if (ssa_op->result_def == var) {
1285 				if (OP1_HAS_RANGE()) {
1286 					if (OP1_RANGE_UNDERFLOW() ||
1287 					    OP1_RANGE_OVERFLOW()) {
1288 						tmp->min = ZEND_LONG_MIN;
1289 						tmp->max = ZEND_LONG_MAX;
1290 					} else {
1291 						zend_long op1_min = OP1_MIN_RANGE();
1292 						zend_long op1_max = OP1_MAX_RANGE();
1293 						tmp->min = ~op1_max;
1294 						tmp->max = ~op1_min;
1295 					}
1296 					return 1;
1297 				}
1298 			}
1299 			break;
1300 		case ZEND_CAST:
1301 			if (ssa_op->op1_def == var) {
1302 				if (ssa_op->op1_def >= 0) {
1303 					if (OP1_HAS_RANGE()) {
1304 						tmp->underflow = OP1_RANGE_UNDERFLOW();
1305 						tmp->min = OP1_MIN_RANGE();
1306 						tmp->max = OP1_MAX_RANGE();
1307 						tmp->overflow  = OP1_RANGE_OVERFLOW();
1308 						return 1;
1309 					}
1310 				}
1311 			} else if (ssa_op->result_def == var) {
1312 				if (opline->extended_value == IS_LONG) {
1313 					if (OP1_HAS_RANGE()) {
1314 						tmp->min = OP1_MIN_RANGE();
1315 						tmp->max = OP1_MAX_RANGE();
1316 						return 1;
1317 					} else {
1318 						tmp->min = ZEND_LONG_MIN;
1319 						tmp->max = ZEND_LONG_MAX;
1320 						return 1;
1321 					}
1322 				}
1323 			}
1324 			break;
1325 		case ZEND_QM_ASSIGN:
1326 		case ZEND_JMP_SET:
1327 		case ZEND_COALESCE:
1328 		case ZEND_COPY_TMP:
1329 			if (ssa_op->op1_def == var) {
1330 				if (ssa_op->op1_def >= 0) {
1331 					if (OP1_HAS_RANGE()) {
1332 						tmp->underflow = OP1_RANGE_UNDERFLOW();
1333 						tmp->min = OP1_MIN_RANGE();
1334 						tmp->max = OP1_MAX_RANGE();
1335 						tmp->overflow  = OP1_RANGE_OVERFLOW();
1336 						return 1;
1337 					}
1338 				}
1339 			}
1340 			if (ssa_op->result_def == var) {
1341 				if (OP1_HAS_RANGE()) {
1342 					tmp->min = OP1_MIN_RANGE();
1343 					tmp->max = OP1_MAX_RANGE();
1344 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1345 					tmp->overflow  = OP1_RANGE_OVERFLOW();
1346 					return 1;
1347 				}
1348 			}
1349 			break;
1350 		case ZEND_SEND_VAR:
1351 			if (ssa_op->op1_def == var) {
1352 				if (ssa_op->op1_def >= 0) {
1353 					if (OP1_HAS_RANGE()) {
1354 						tmp->underflow = OP1_RANGE_UNDERFLOW();
1355 						tmp->min = OP1_MIN_RANGE();
1356 						tmp->max = OP1_MAX_RANGE();
1357 						tmp->overflow  = OP1_RANGE_OVERFLOW();
1358 						return 1;
1359 					}
1360 				}
1361 			}
1362 			break;
1363 		case ZEND_PRE_INC:
1364 			if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1365 				if (OP1_HAS_RANGE()) {
1366 					tmp->min = OP1_MIN_RANGE();
1367 					tmp->max = OP1_MAX_RANGE();
1368 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1369 					tmp->overflow = OP1_RANGE_OVERFLOW();
1370 					if (tmp->max < ZEND_LONG_MAX) {
1371 						tmp->max++;
1372 					} else {
1373 						tmp->overflow = 1;
1374 					}
1375 					if (tmp->min < ZEND_LONG_MAX && !tmp->underflow) {
1376 						tmp->min++;
1377 					}
1378 					return 1;
1379 				}
1380 			}
1381 			break;
1382 		case ZEND_PRE_DEC:
1383 			if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1384 				if (OP1_HAS_RANGE()) {
1385 					tmp->min = OP1_MIN_RANGE();
1386 					tmp->max = OP1_MAX_RANGE();
1387 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1388 					tmp->overflow = OP1_RANGE_OVERFLOW();
1389 					if (tmp->min > ZEND_LONG_MIN) {
1390 						tmp->min--;
1391 					} else {
1392 						tmp->underflow = 1;
1393 					}
1394 					if (tmp->max > ZEND_LONG_MIN && !tmp->overflow) {
1395 						tmp->max--;
1396 					}
1397 					return 1;
1398 				}
1399 			}
1400 			break;
1401 		case ZEND_POST_INC:
1402 			if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1403 				if (OP1_HAS_RANGE()) {
1404 					tmp->min = OP1_MIN_RANGE();
1405 					tmp->max = OP1_MAX_RANGE();
1406 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1407 					tmp->overflow = OP1_RANGE_OVERFLOW();
1408 					if (ssa_op->result_def == var) {
1409 						return 1;
1410 					}
1411 					if (tmp->max < ZEND_LONG_MAX) {
1412 						tmp->max++;
1413 					} else {
1414 						tmp->overflow = 1;
1415 					}
1416 					if (tmp->min < ZEND_LONG_MAX && !tmp->underflow) {
1417 						tmp->min++;
1418 					}
1419 					return 1;
1420 				}
1421 			}
1422 			break;
1423 		case ZEND_POST_DEC:
1424 			if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1425 				if (OP1_HAS_RANGE()) {
1426 					tmp->min = OP1_MIN_RANGE();
1427 					tmp->max = OP1_MAX_RANGE();
1428 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1429 					tmp->overflow = OP1_RANGE_OVERFLOW();
1430 					if (ssa_op->result_def == var) {
1431 						return 1;
1432 					}
1433 					if (tmp->min > ZEND_LONG_MIN) {
1434 						tmp->min--;
1435 					} else {
1436 						tmp->underflow = 1;
1437 					}
1438 					if (tmp->max > ZEND_LONG_MIN && !tmp->overflow) {
1439 						tmp->max--;
1440 					}
1441 					return 1;
1442 				}
1443 			}
1444 			break;
1445 		case ZEND_UNSET_DIM:
1446 		case ZEND_UNSET_OBJ:
1447 			if (ssa_op->op1_def == var) {
1448 				/* If op1 is scalar, UNSET_DIM and UNSET_OBJ have no effect, so we can keep
1449 				 * the previous ranges. */
1450 				if (OP1_HAS_RANGE()) {
1451 					tmp->min = OP1_MIN_RANGE();
1452 					tmp->max = OP1_MAX_RANGE();
1453 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1454 					tmp->overflow  = OP1_RANGE_OVERFLOW();
1455 					return 1;
1456 				}
1457 			}
1458 			break;
1459 		case ZEND_ASSIGN:
1460 			if (ssa_op->op1_def == var || ssa_op->op2_def == var || ssa_op->result_def == var) {
1461 				if (OP2_HAS_RANGE()) {
1462 					tmp->min = OP2_MIN_RANGE();
1463 					tmp->max = OP2_MAX_RANGE();
1464 					tmp->underflow = OP2_RANGE_UNDERFLOW();
1465 					tmp->overflow  = OP2_RANGE_OVERFLOW();
1466 					return 1;
1467 				}
1468 			}
1469 			break;
1470 		case ZEND_ASSIGN_DIM:
1471 		case ZEND_ASSIGN_OBJ:
1472 		case ZEND_ASSIGN_STATIC_PROP:
1473 		case ZEND_ASSIGN_DIM_OP:
1474 		case ZEND_ASSIGN_OBJ_OP:
1475 		case ZEND_ASSIGN_STATIC_PROP_OP:
1476 			if ((ssa_op+1)->op1_def == var) {
1477 				opline++;
1478 				ssa_op++;
1479 				if (OP1_HAS_RANGE()) {
1480 					tmp->min = OP1_MIN_RANGE();
1481 					tmp->max = OP1_MAX_RANGE();
1482 					tmp->underflow = OP1_RANGE_UNDERFLOW();
1483 					tmp->overflow  = OP1_RANGE_OVERFLOW();
1484 				}
1485 				return 1;
1486 			}
1487 			break;
1488 		case ZEND_ASSIGN_OP:
1489 			if (opline->extended_value != ZEND_CONCAT
1490 			 && opline->extended_value != ZEND_POW) {
1491 				if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1492 					return zend_inference_calc_binary_op_range(
1493 						op_array, ssa, opline, ssa_op,
1494 						opline->extended_value, tmp);
1495 				}
1496 			}
1497 			break;
1498 		case ZEND_OP_DATA:
1499 			if (ssa_op->op1_def == var) {
1500 				if ((opline-1)->opcode == ZEND_ASSIGN_DIM ||
1501 				    (opline-1)->opcode == ZEND_ASSIGN_OBJ ||
1502 				    (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP ||
1503 				    (opline-1)->opcode == ZEND_ASSIGN_DIM_OP ||
1504 				    (opline-1)->opcode == ZEND_ASSIGN_OBJ_OP ||
1505 				    (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
1506 					if (OP1_HAS_RANGE()) {
1507 						tmp->min = OP1_MIN_RANGE();
1508 						tmp->max = OP1_MAX_RANGE();
1509 						tmp->underflow = OP1_RANGE_UNDERFLOW();
1510 						tmp->overflow  = OP1_RANGE_OVERFLOW();
1511 						return 1;
1512 					}
1513 				}
1514 				break;
1515 			}
1516 			break;
1517 		case ZEND_RECV:
1518 		case ZEND_RECV_INIT:
1519 			if (ssa_op->result_def == var) {
1520 				if (op_array->arg_info &&
1521 				    opline->op1.num <= op_array->num_args) {
1522 					zend_type type = op_array->arg_info[opline->op1.num-1].type;
1523 					uint32_t mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(type);
1524 					if (mask == MAY_BE_LONG) {
1525 						tmp->underflow = 0;
1526 						tmp->min = ZEND_LONG_MIN;
1527 						tmp->max = ZEND_LONG_MAX;
1528 						tmp->overflow = 0;
1529 						return 1;
1530 					}
1531 				}
1532 			}
1533 			break;
1534 		case ZEND_STRLEN:
1535 			if (ssa_op->result_def == var) {
1536 #if SIZEOF_ZEND_LONG == 4
1537 				/* The length of a string is a non-negative integer. However, on 32-bit
1538 				 * platforms overflows into negative lengths may occur, so it's better
1539 				 * to not assume any particular range. */
1540 				tmp->min = ZEND_LONG_MIN;
1541 #else
1542 				tmp->min = 0;
1543 #endif
1544 				tmp->max = ZEND_LONG_MAX;
1545 				return 1;
1546 			}
1547 			break;
1548 		case ZEND_FUNC_NUM_ARGS:
1549 			tmp->min = 0;
1550 			tmp->max = ZEND_LONG_MAX;
1551 			return 1;
1552 		case ZEND_COUNT:
1553 			/* count() on Countable objects may return negative numbers */
1554 			tmp->min = ZEND_LONG_MIN;
1555 			tmp->max = ZEND_LONG_MAX;
1556 			return 1;
1557 		case ZEND_DO_FCALL:
1558 		case ZEND_DO_ICALL:
1559 		case ZEND_DO_UCALL:
1560 		case ZEND_DO_FCALL_BY_NAME:
1561 			if (ssa_op->result_def == var) {
1562 				const zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
1563 				const zend_call_info *call_info;
1564 				if (!func_info || !func_info->call_map) {
1565 					break;
1566 				}
1567 
1568 				call_info = func_info->call_map[opline - op_array->opcodes];
1569 				if (!call_info || call_info->is_prototype) {
1570 					break;
1571 				}
1572 				if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
1573 					func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
1574 					if (func_info && func_info->return_info.has_range) {
1575 						*tmp = func_info->return_info.range;
1576 						return 1;
1577 					}
1578 				}
1579 //TODO: we can't use type inference for internal functions at this point ???
1580 #if 0
1581 					uint32_t type;
1582 
1583 					type = zend_get_func_info(call_info, ssa);
1584 					if (!(type & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)))) {
1585 						tmp->underflow = 0;
1586 						tmp->min = 0;
1587 						tmp->max = 0;
1588 						tmp->overflow = 0;
1589 						if (type & MAY_BE_LONG) {
1590 							tmp->min = ZEND_LONG_MIN;
1591 							tmp->max = ZEND_LONG_MAX;
1592 						} else if (type & MAY_BE_TRUE) {
1593 							if (!(type & (MAY_BE_NULL|MAY_BE_FALSE))) {
1594 								tmp->min = 1;
1595 							}
1596 							tmp->max = 1;
1597 						}
1598 						return 1;
1599 					}
1600 #endif
1601 			}
1602 			break;
1603 		// FIXME: support for more opcodes
1604 		default:
1605 			break;
1606 	}
1607 	return 0;
1608 }
1609 
zend_inference_init_range(const zend_op_array * op_array,zend_ssa * ssa,int var,bool underflow,zend_long min,zend_long max,bool overflow)1610 static void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int var, bool underflow, zend_long min, zend_long max, bool overflow)
1611 {
1612 	if (underflow) {
1613 		min = ZEND_LONG_MIN;
1614 	}
1615 	if (overflow) {
1616 		max = ZEND_LONG_MAX;
1617 	}
1618 	ssa->var_info[var].has_range = 1;
1619 	ssa->var_info[var].range.underflow = underflow;
1620 	ssa->var_info[var].range.min = min;
1621 	ssa->var_info[var].range.max = max;
1622 	ssa->var_info[var].range.overflow = overflow;
1623 	LOG_SSA_RANGE("  change range (init      SCC %2d) %2d [%s%ld..%ld%s]\n", ssa->vars[var].scc, var, (underflow?"-- ":""), min, max, (overflow?" ++":""));
1624 }
1625 
zend_inference_widening_meet(zend_ssa_var_info * var_info,zend_ssa_range * r)1626 static bool zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r)
1627 {
1628 	if (!var_info->has_range) {
1629 		var_info->has_range = 1;
1630 	} else {
1631 		if (r->underflow ||
1632 		    var_info->range.underflow ||
1633 		    r->min < var_info->range.min) {
1634 			r->underflow = 1;
1635 			r->min = ZEND_LONG_MIN;
1636 		}
1637 		if (r->overflow ||
1638 		    var_info->range.overflow ||
1639 		    r->max > var_info->range.max) {
1640 			r->overflow = 1;
1641 			r->max = ZEND_LONG_MAX;
1642 		}
1643 		if (var_info->range.min == r->min &&
1644 		    var_info->range.max == r->max &&
1645 		    var_info->range.underflow == r->underflow &&
1646 		    var_info->range.overflow == r->overflow) {
1647 			return 0;
1648 		}
1649 	}
1650 	var_info->range = *r;
1651 	return 1;
1652 }
1653 
zend_ssa_range_widening(const zend_op_array * op_array,zend_ssa * ssa,int var,int scc)1654 static bool zend_ssa_range_widening(const zend_op_array *op_array, zend_ssa *ssa, int var, int scc)
1655 {
1656 	zend_ssa_range tmp;
1657 
1658 	if (zend_inference_calc_range(op_array, ssa, var, 1, 0, &tmp)) {
1659 		if (zend_inference_widening_meet(&ssa->var_info[var], &tmp)) {
1660 			LOG_SSA_RANGE("  change range (widening  SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
1661 			return 1;
1662 		}
1663 	}
1664 	return 0;
1665 }
1666 
zend_inference_narrowing_meet(zend_ssa_var_info * var_info,zend_ssa_range * r)1667 static bool zend_inference_narrowing_meet(zend_ssa_var_info *var_info, zend_ssa_range *r)
1668 {
1669 	if (!var_info->has_range) {
1670 		var_info->has_range = 1;
1671 	} else {
1672 		if (!r->underflow &&
1673 		    !var_info->range.underflow &&
1674 		    var_info->range.min < r->min) {
1675 			r->min = var_info->range.min;
1676 		}
1677 		if (!r->overflow &&
1678 		    !var_info->range.overflow &&
1679 		    var_info->range.max > r->max) {
1680 			r->max = var_info->range.max;
1681 		}
1682 		if (r->underflow) {
1683 			r->min = ZEND_LONG_MIN;
1684 		}
1685 		if (r->overflow) {
1686 			r->max = ZEND_LONG_MAX;
1687 		}
1688 		if (var_info->range.min == r->min &&
1689 		    var_info->range.max == r->max &&
1690 		    var_info->range.underflow == r->underflow &&
1691 		    var_info->range.overflow == r->overflow) {
1692 			return 0;
1693 		}
1694 	}
1695 	var_info->range = *r;
1696 	return 1;
1697 }
1698 
zend_ssa_range_narrowing(const zend_op_array * op_array,zend_ssa * ssa,int var,int scc)1699 static bool zend_ssa_range_narrowing(const zend_op_array *op_array, zend_ssa *ssa, int var, int scc)
1700 {
1701 	zend_ssa_range tmp;
1702 
1703 	if (zend_inference_calc_range(op_array, ssa, var, 0, 1, &tmp)) {
1704 		if (zend_inference_narrowing_meet(&ssa->var_info[var], &tmp)) {
1705 			LOG_SSA_RANGE("  change range (narrowing SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
1706 			return 1;
1707 		}
1708 	}
1709 	return 0;
1710 }
1711 
1712 #ifdef NEG_RANGE
1713 # define CHECK_INNER_CYCLE(var2) \
1714 	do { \
1715 		if (ssa->vars[var2].scc == ssa->vars[var].scc && \
1716 		    !ssa->vars[var2].scc_entry && \
1717 		    !zend_bitset_in(visited, var2) && \
1718 			zend_check_inner_cycles(op_array, ssa, worklist, visited, var2)) { \
1719 			return 1; \
1720 		} \
1721 	} while (0)
1722 
zend_check_inner_cycles(const zend_op_array * op_array,zend_ssa * ssa,zend_bitset worklist,zend_bitset visited,int var)1723 static bool zend_check_inner_cycles(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset worklist, zend_bitset visited, int var)
1724 {
1725 	if (zend_bitset_in(worklist, var)) {
1726 		return 1;
1727 	}
1728 	zend_bitset_incl(worklist, var);
1729 	FOR_EACH_VAR_USAGE(var, CHECK_INNER_CYCLE);
1730 	zend_bitset_incl(visited, var);
1731 	return 0;
1732 }
1733 #endif
1734 
zend_infer_ranges_warmup(const zend_op_array * op_array,zend_ssa * ssa,const int * scc_var,const int * next_scc_var,int scc)1735 static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ssa, const int *scc_var, const int *next_scc_var, int scc)
1736 {
1737 	int worklist_len = zend_bitset_len(ssa->vars_count);
1738 	int j, n;
1739 	zend_ssa_range tmp;
1740 	ALLOCA_FLAG(use_heap)
1741 	zend_bitset worklist = do_alloca(sizeof(zend_ulong) * worklist_len * 2, use_heap);
1742 	zend_bitset visited = worklist + worklist_len;
1743 #ifdef NEG_RANGE
1744 	int has_inner_cycles = 0;
1745 
1746 	memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
1747 	memset(visited, 0, sizeof(zend_ulong) * worklist_len);
1748 	j = scc_var[scc];
1749 	while (j >= 0) {
1750 		if (!zend_bitset_in(visited, j) &&
1751 		    zend_check_inner_cycles(op_array, ssa, worklist, visited, j)) {
1752 			has_inner_cycles = 1;
1753 			break;
1754 		}
1755 		j = next_scc_var[j];
1756 	}
1757 #endif
1758 
1759 	memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
1760 
1761 	for (n = 0; n < RANGE_WARMUP_PASSES; n++) {
1762 		j= scc_var[scc];
1763 		while (j >= 0) {
1764 			if (ssa->vars[j].scc_entry
1765 			 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1766 				zend_bitset_incl(worklist, j);
1767 			}
1768 			j = next_scc_var[j];
1769 		}
1770 
1771 		memset(visited, 0, sizeof(zend_ulong) * worklist_len);
1772 
1773 		WHILE_WORKLIST(worklist, worklist_len, j) {
1774 			if (zend_inference_calc_range(op_array, ssa, j, 0, 0, &tmp)) {
1775 #ifdef NEG_RANGE
1776 				if (!has_inner_cycles &&
1777 				    ssa->var_info[j].has_range &&
1778 				    ssa->vars[j].definition_phi &&
1779 				    ssa->vars[j].definition_phi->pi >= 0 &&
1780 					ssa->vars[j].definition_phi->has_range_constraint &&
1781 				    ssa->vars[j].definition_phi->constraint.range.negative &&
1782 				    ssa->vars[j].definition_phi->constraint.range.min_ssa_var < 0 &&
1783 				    ssa->vars[j].definition_phi->constraint.range.max_ssa_var < 0) {
1784 					zend_ssa_range_constraint *constraint =
1785 						&ssa->vars[j].definition_phi->constraint.range;
1786 					if (tmp.min == ssa->var_info[j].range.min &&
1787 					    tmp.max == ssa->var_info[j].range.max) {
1788 						if (constraint->negative == NEG_INIT) {
1789 							LOG_NEG_RANGE("#%d INVARIANT\n", j);
1790 							constraint->negative = NEG_INVARIANT;
1791 						}
1792 					} else if (tmp.min == ssa->var_info[j].range.min &&
1793 					           tmp.max == ssa->var_info[j].range.max + 1 &&
1794 					           tmp.max < constraint->range.min) {
1795 						if (constraint->negative == NEG_INIT ||
1796 						    constraint->negative == NEG_INVARIANT) {
1797 							LOG_NEG_RANGE("#%d LT\n", j);
1798 							constraint->negative = NEG_USE_LT;
1799 //???NEG
1800 						} else if (constraint->negative == NEG_USE_GT) {
1801 							LOG_NEG_RANGE("#%d UNKNOWN\n", j);
1802 							constraint->negative = NEG_UNKNOWN;
1803 						}
1804 					} else if (tmp.max == ssa->var_info[j].range.max &&
1805 				               tmp.min == ssa->var_info[j].range.min - 1 &&
1806 					           tmp.min > constraint->range.max) {
1807 						if (constraint->negative == NEG_INIT ||
1808 						    constraint->negative == NEG_INVARIANT) {
1809 							LOG_NEG_RANGE("#%d GT\n", j);
1810 							constraint->negative = NEG_USE_GT;
1811 //???NEG
1812 						} else if (constraint->negative == NEG_USE_LT) {
1813 							LOG_NEG_RANGE("#%d UNKNOWN\n", j);
1814 							constraint->negative = NEG_UNKNOWN;
1815 						}
1816 					} else {
1817 						LOG_NEG_RANGE("#%d UNKNOWN\n", j);
1818 						constraint->negative = NEG_UNKNOWN;
1819 					}
1820 				}
1821 #endif
1822 				if (zend_inference_narrowing_meet(&ssa->var_info[j], &tmp)) {
1823 					LOG_SSA_RANGE("  change range (warmup %2d SCC %2d) %2d [%s%ld..%ld%s]\n", n, scc, j, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
1824 					zend_bitset_incl(visited, j);
1825 					FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR_1);
1826 				}
1827 			}
1828 		} WHILE_WORKLIST_END();
1829 	}
1830 	free_alloca(worklist, use_heap);
1831 }
1832 
zend_infer_ranges(const zend_op_array * op_array,zend_ssa * ssa)1833 static void zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
1834 {
1835 	int worklist_len = zend_bitset_len(ssa->vars_count);
1836 	zend_bitset worklist;
1837 	int *next_scc_var;
1838 	int *scc_var;
1839 	zend_ssa_phi *p;
1840 	zend_ssa_range tmp;
1841 	int scc, j;
1842 	ALLOCA_FLAG(use_heap);
1843 
1844 	worklist = do_alloca(
1845 		ZEND_MM_ALIGNED_SIZE(sizeof(zend_ulong) * worklist_len) +
1846 		ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->vars_count) +
1847 		sizeof(int) * ssa->sccs, use_heap);
1848 	next_scc_var = (int*)((char*)worklist + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ulong) * worklist_len));
1849 	scc_var = (int*)((char*)next_scc_var + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->vars_count));
1850 
1851 	LOG_SSA_RANGE("Range Inference\n");
1852 
1853 	/* Create linked lists of SSA variables for each SCC */
1854 	memset(scc_var, -1, sizeof(int) * ssa->sccs);
1855 	for (j = 0; j < ssa->vars_count; j++) {
1856 		if (ssa->vars[j].scc >= 0) {
1857 			next_scc_var[j] = scc_var[ssa->vars[j].scc];
1858 			scc_var[ssa->vars[j].scc] = j;
1859 		}
1860 	}
1861 
1862 	for (scc = 0; scc < ssa->sccs; scc++) {
1863 		j = scc_var[scc];
1864 		if (next_scc_var[j] < 0) {
1865 			/* SCC with a single element */
1866 			if (ssa->var_info[j].type & MAY_BE_REF) {
1867 				/* pass */
1868 			} else if (zend_inference_calc_range(op_array, ssa, j, 0, 1, &tmp)) {
1869 				zend_inference_init_range(op_array, ssa, j, tmp.underflow, tmp.min, tmp.max, tmp.overflow);
1870 			} else {
1871 				zend_inference_init_range(op_array, ssa, j, 1, ZEND_LONG_MIN, ZEND_LONG_MAX, 1);
1872 			}
1873 		} else {
1874 			/* Find SCC entry points */
1875 			memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
1876 			do {
1877 				if (ssa->vars[j].scc_entry
1878 				 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1879 					zend_bitset_incl(worklist, j);
1880 				}
1881 				j = next_scc_var[j];
1882 			} while (j >= 0);
1883 
1884 #if RANGE_WARMUP_PASSES > 0
1885 			zend_infer_ranges_warmup(op_array, ssa, scc_var, next_scc_var, scc);
1886 			j = scc_var[scc];
1887 			do {
1888 				if (!(ssa->var_info[j].type & MAY_BE_REF)) {
1889 					zend_bitset_incl(worklist, j);
1890 				}
1891 				j = next_scc_var[j];
1892 			} while (j >= 0);
1893 #endif
1894 
1895 			/* widening */
1896 			WHILE_WORKLIST(worklist, worklist_len, j) {
1897 				if (zend_ssa_range_widening(op_array, ssa, j, scc)) {
1898 					FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1899 				}
1900 			} WHILE_WORKLIST_END();
1901 
1902 			/* initialize missing ranges */
1903 			for (j = scc_var[scc]; j >= 0; j = next_scc_var[j]) {
1904 				if (!ssa->var_info[j].has_range
1905 				 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1906 					zend_inference_init_range(op_array, ssa, j, 1, ZEND_LONG_MIN, ZEND_LONG_MAX, 1);
1907 					FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1908 				}
1909 			}
1910 
1911 			/* widening (second round) */
1912 			WHILE_WORKLIST(worklist, worklist_len, j) {
1913 				if (zend_ssa_range_widening(op_array, ssa, j, scc)) {
1914 					FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1915 				}
1916 			} WHILE_WORKLIST_END();
1917 
1918 			/* Add all SCC entry variables into worklist for narrowing */
1919 			for (j = scc_var[scc]; j >= 0; j = next_scc_var[j]) {
1920 				if (ssa->vars[j].definition_phi
1921 				 && ssa->vars[j].definition_phi->pi < 0
1922 				 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1923 					/* narrowing Phi functions first */
1924 					zend_ssa_range_narrowing(op_array, ssa, j, scc);
1925 				}
1926 				zend_bitset_incl(worklist, j);
1927 			}
1928 
1929 			/* narrowing */
1930 			WHILE_WORKLIST(worklist, worklist_len, j) {
1931 				if (zend_ssa_range_narrowing(op_array, ssa, j, scc)) {
1932 					FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1933 #ifdef SYM_RANGE
1934 					/* Process symbolic control-flow constraints */
1935 					p = ssa->vars[j].sym_use_chain;
1936 					while (p) {
1937 						ADD_SCC_VAR(p->ssa_var);
1938 						p = p->sym_use_chain;
1939 					}
1940 #endif
1941 				}
1942 			} WHILE_WORKLIST_END();
1943 		}
1944 	}
1945 
1946 	free_alloca(worklist, use_heap);
1947 }
1948 /* }}} */
1949 
get_ssa_alias_types(zend_ssa_alias_kind alias)1950 static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
1951 	if (alias == HTTP_RESPONSE_HEADER_ALIAS) {
1952 		return MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_RC1 | MAY_BE_RCN;
1953 	} else {
1954 		return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1955 	}
1956 }
1957 
1958 #define UPDATE_SSA_TYPE(_type, _var)									\
1959 	do {																\
1960 		uint32_t __type = (_type) & ~MAY_BE_GUARD;						\
1961 		int __var = (_var);												\
1962 		if (__type & MAY_BE_REF) {										\
1963 			__type |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; \
1964 		}																\
1965 		if (__var >= 0) {												\
1966 			zend_ssa_var *__ssa_var = &ssa_vars[__var];					\
1967 			if (__ssa_var->var < op_array->num_args) {					\
1968 				if (__type & MAY_BE_RC1) {                              \
1969 					/* TODO: may be captured by exception backtreace */ \
1970 					__type |= MAY_BE_RCN;                               \
1971 				}                                                       \
1972 			}                                                           \
1973 			if (__ssa_var->var < op_array->last_var) {					\
1974 				if (__type & (MAY_BE_REF|MAY_BE_RCN)) {					\
1975 					__type |= MAY_BE_RC1 | MAY_BE_RCN;					\
1976 				}														\
1977 				if ((__type & MAY_BE_RC1) && (__type & MAY_BE_STRING)) {\
1978 					/* TODO: support for array keys and ($str . "")*/   \
1979 					__type |= MAY_BE_RCN;                               \
1980 				}                                                       \
1981 				if (__ssa_var->alias) {									\
1982 					__type |= get_ssa_alias_types(__ssa_var->alias);	\
1983 				}														\
1984 			}															\
1985 			if (ssa_var_info[__var].type != __type) { 					\
1986 				ZEND_ASSERT(ssa_opcodes != NULL ||						\
1987 					__ssa_var->var >= op_array->last_var ||				\
1988 					(ssa_var_info[__var].type & MAY_BE_REF)				\
1989 						== (__type & MAY_BE_REF));						\
1990 				if (ssa_var_info[__var].type & ~__type) {				\
1991 					emit_type_narrowing_warning(op_array, ssa, __var);	\
1992 					return FAILURE;										\
1993 				}														\
1994 				ssa_var_info[__var].type = __type;						\
1995 				if (update_worklist) { 									\
1996 					add_usages(op_array, ssa, worklist, __var);			\
1997 				}														\
1998 			}															\
1999 			/*zend_bitset_excl(worklist, var);*/						\
2000 		}																\
2001 	} while (0)
2002 
2003 #define UPDATE_SSA_OBJ_TYPE(_ce, _is_instanceof, var)				    \
2004 	do {                                                                \
2005 		if (var >= 0) {													\
2006 			if (ssa_var_info[var].ce != (_ce) ||                        \
2007 			    ssa_var_info[var].is_instanceof != (_is_instanceof)) {  \
2008 				ssa_var_info[var].ce = (_ce);						    \
2009 				ssa_var_info[var].is_instanceof = (_is_instanceof);     \
2010 				if (update_worklist) { 									\
2011 					add_usages(op_array, ssa, worklist, var);			\
2012 				}														\
2013 			}															\
2014 			/*zend_bitset_excl(worklist, var);*/						\
2015 		}																\
2016 	} while (0)
2017 
2018 #define COPY_SSA_OBJ_TYPE(from_var, to_var) do { \
2019 	if ((from_var) >= 0 && (ssa_var_info[(from_var)].type & MAY_BE_OBJECT) \
2020 			&& ssa_var_info[(from_var)].ce && !(ssa_var_info[(to_var)].type & MAY_BE_REF)) { \
2021 		UPDATE_SSA_OBJ_TYPE(ssa_var_info[(from_var)].ce, \
2022 			ssa_var_info[(from_var)].is_instanceof, (to_var)); \
2023 	} else { \
2024 		UPDATE_SSA_OBJ_TYPE(NULL, 0, (to_var)); \
2025 	} \
2026 } while (0)
2027 
add_usages(const zend_op_array * op_array,zend_ssa * ssa,zend_bitset worklist,int var)2028 static void add_usages(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset worklist, int var)
2029 {
2030 	if (ssa->vars[var].phi_use_chain) {
2031 		zend_ssa_phi *p = ssa->vars[var].phi_use_chain;
2032 		do {
2033 			zend_bitset_incl(worklist, p->ssa_var);
2034 			p = zend_ssa_next_use_phi(ssa, var, p);
2035 		} while (p);
2036 	}
2037 	if (ssa->vars[var].use_chain >= 0) {
2038 		int use = ssa->vars[var].use_chain;
2039 		zend_ssa_op *op;
2040 
2041 		do {
2042 			op = ssa->ops + use;
2043 			if (op->result_def >= 0) {
2044 				zend_bitset_incl(worklist, op->result_def);
2045 			}
2046 			if (op->op1_def >= 0) {
2047 				zend_bitset_incl(worklist, op->op1_def);
2048 			}
2049 			if (op->op2_def >= 0) {
2050 				zend_bitset_incl(worklist, op->op2_def);
2051 			}
2052 			if (op_array->opcodes[use].opcode == ZEND_OP_DATA) {
2053 				op--;
2054 				if (op->result_def >= 0) {
2055 					zend_bitset_incl(worklist, op->result_def);
2056 				}
2057 				if (op->op1_def >= 0) {
2058 					zend_bitset_incl(worklist, op->op1_def);
2059 				}
2060 				if (op->op2_def >= 0) {
2061 					zend_bitset_incl(worklist, op->op2_def);
2062 				}
2063 			} else if (use + 1 < op_array->last
2064 			 && op_array->opcodes[use + 1].opcode == ZEND_OP_DATA) {
2065 				op++;
2066 				if (op->result_def >= 0) {
2067 					zend_bitset_incl(worklist, op->result_def);
2068 				}
2069 				if (op->op1_def >= 0) {
2070 					zend_bitset_incl(worklist, op->op1_def);
2071 				}
2072 				if (op->op2_def >= 0) {
2073 					zend_bitset_incl(worklist, op->op2_def);
2074 				}
2075 			}
2076 			use = zend_ssa_next_use(ssa->ops, var, use);
2077 		} while (use >= 0);
2078 	}
2079 }
2080 
emit_type_narrowing_warning(const zend_op_array * op_array,zend_ssa * ssa,int var)2081 static void emit_type_narrowing_warning(const zend_op_array *op_array, zend_ssa *ssa, int var)
2082 {
2083 	int def_op_num = ssa->vars[var].definition;
2084 	const zend_op *def_opline = def_op_num >= 0 ? &op_array->opcodes[def_op_num] : NULL;
2085 	const char *def_op_name = def_opline ? zend_get_opcode_name(def_opline->opcode) : "PHI";
2086 	uint32_t lineno = def_opline ? def_opline->lineno : 0;
2087 	zend_error_at(
2088 		E_WARNING, op_array->filename, lineno,
2089 		"Narrowing occurred during type inference of %s. Please file a bug report on https://github.com/php/php-src/issues", def_op_name);
2090 #if ZEND_DEBUG
2091 	ZEND_ASSERT(0 && "Narrowing during type inference");
2092 #endif
2093 }
2094 
zend_array_type_info(const zval * zv)2095 ZEND_API uint32_t ZEND_FASTCALL zend_array_type_info(const zval *zv)
2096 {
2097 	HashTable *ht = Z_ARRVAL_P(zv);
2098 	uint32_t tmp = MAY_BE_ARRAY;
2099 	zend_string *str;
2100 	zval *val;
2101 
2102 	if (Z_REFCOUNTED_P(zv)) {
2103 		tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2104 	} else {
2105 		tmp |= MAY_BE_RCN;
2106 	}
2107 
2108 	if (zend_hash_num_elements(ht) == 0) {
2109 		tmp |=  MAY_BE_ARRAY_EMPTY;
2110 	} else if (HT_IS_PACKED(ht)) {
2111 		tmp |= MAY_BE_ARRAY_PACKED;
2112 		ZEND_HASH_PACKED_FOREACH_VAL(ht, val) {
2113 			tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
2114 		} ZEND_HASH_FOREACH_END();
2115 	} else {
2116 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, str, val) {
2117 			if (str) {
2118 				tmp |= MAY_BE_ARRAY_STRING_HASH;
2119 			} else {
2120 				tmp |= MAY_BE_ARRAY_NUMERIC_HASH;
2121 			}
2122 			tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
2123 		} ZEND_HASH_FOREACH_END();
2124 	}
2125 	return tmp;
2126 }
2127 
2128 
zend_array_element_type(uint32_t t1,uint8_t op_type,int write,int insert)2129 ZEND_API uint32_t zend_array_element_type(uint32_t t1, uint8_t op_type, int write, int insert)
2130 {
2131 	uint32_t tmp = 0;
2132 
2133 	if (t1 & MAY_BE_OBJECT) {
2134 	    if (!write) {
2135 			/* can't be REF  because of ZVAL_COPY_DEREF() usage */
2136 			tmp |= MAY_BE_ANY | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2137 		} else {
2138 			tmp |= MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2139 	    }
2140 		if (write) {
2141 			tmp |= MAY_BE_INDIRECT;
2142 		}
2143 	}
2144 	if (t1 & MAY_BE_ARRAY) {
2145 		if (insert) {
2146 			tmp |= MAY_BE_NULL;
2147 		} else {
2148 			tmp |= MAY_BE_NULL | ((t1 & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
2149 			if (tmp & MAY_BE_ARRAY) {
2150 				tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2151 			}
2152 			if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2153 				if (!write) {
2154 					/* can't be REF  because of ZVAL_COPY_DEREF() usage */
2155 					tmp |= MAY_BE_RCN;
2156 					if ((op_type & (IS_VAR|IS_TMP_VAR)) && (t1 & MAY_BE_RC1)) {
2157 						tmp |= MAY_BE_RC1;
2158 					}
2159 				} else if (t1 & MAY_BE_ARRAY_OF_REF) {
2160 					tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
2161 				} else {
2162 					tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2163 				}
2164 			}
2165 		}
2166 		if (write) {
2167 			tmp |= MAY_BE_INDIRECT;
2168 		}
2169 	}
2170 	if (t1 & MAY_BE_STRING) {
2171 		tmp |= MAY_BE_STRING | MAY_BE_RC1;
2172 		if (write) {
2173 			tmp |= MAY_BE_NULL;
2174 		}
2175 	}
2176 	if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2177 		tmp |= MAY_BE_NULL;
2178 		if (write) {
2179 			tmp |= MAY_BE_INDIRECT;
2180 		}
2181 	}
2182 	if (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
2183 		if (!write) {
2184 			tmp |= MAY_BE_NULL;
2185 		}
2186 	}
2187 	return tmp;
2188 }
2189 
assign_dim_array_result_type(uint32_t arr_type,uint32_t dim_type,uint32_t value_type,uint8_t dim_op_type)2190 static uint32_t assign_dim_array_result_type(
2191 		uint32_t arr_type, uint32_t dim_type, uint32_t value_type, uint8_t dim_op_type) {
2192 	uint32_t tmp = 0;
2193 	/* Only add key type if we have a value type. We want to maintain the invariant that a
2194 	 * key type exists iff a value type exists even in dead code that may use empty types. */
2195 	if (value_type & (MAY_BE_ANY|MAY_BE_UNDEF)) {
2196 		if (value_type & MAY_BE_UNDEF) {
2197 			value_type |= MAY_BE_NULL;
2198 		}
2199 		if (dim_op_type == IS_UNUSED) {
2200 			if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2201 				tmp |= MAY_BE_ARRAY_PACKED;
2202 			}
2203 			tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2204 		} else {
2205 			if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
2206 				if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2207 					tmp |= MAY_BE_ARRAY_PACKED;
2208 				}
2209 				tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2210 			}
2211 			if (dim_type & MAY_BE_STRING) {
2212 				tmp |= MAY_BE_ARRAY_KEY_STRING;
2213 				if (dim_op_type != IS_CONST) {
2214 					// FIXME: numeric string
2215 					if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2216 						tmp |= MAY_BE_ARRAY_PACKED;
2217 					}
2218 					tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2219 				}
2220 			}
2221 			if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
2222 				tmp |= MAY_BE_ARRAY_KEY_STRING;
2223 			}
2224 		}
2225 	}
2226 	/* Only add value type if we have a key type. It might be that the key type is illegal
2227 	 * for arrays. */
2228 	if (tmp & MAY_BE_ARRAY_KEY_ANY) {
2229 		tmp |= (value_type & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
2230 	}
2231 	tmp &= ~MAY_BE_ARRAY_EMPTY;
2232 	return tmp;
2233 }
2234 
assign_dim_result_type(uint32_t arr_type,uint32_t dim_type,uint32_t value_type,uint8_t dim_op_type)2235 static uint32_t assign_dim_result_type(
2236 		uint32_t arr_type, uint32_t dim_type, uint32_t value_type, uint8_t dim_op_type) {
2237 	uint32_t tmp = arr_type & ~(MAY_BE_RC1|MAY_BE_RCN);
2238 
2239 	if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2240 		tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE);
2241 		tmp |= MAY_BE_ARRAY|MAY_BE_RC1;
2242 	}
2243 	if (tmp & (MAY_BE_ARRAY|MAY_BE_STRING)) {
2244 		tmp |= MAY_BE_RC1;
2245 	}
2246 	if (tmp & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2247 		tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2248 	}
2249 	if (tmp & MAY_BE_ARRAY) {
2250 		tmp |= assign_dim_array_result_type(arr_type, dim_type, value_type, dim_op_type);
2251 	}
2252 	return tmp;
2253 }
2254 
2255 /* For binary ops that have compound assignment operators */
binary_op_result_type(zend_ssa * ssa,uint8_t opcode,uint32_t t1,uint32_t t2,int result_var,zend_long optimization_level)2256 static uint32_t binary_op_result_type(
2257 		zend_ssa *ssa, uint8_t opcode, uint32_t t1, uint32_t t2, int result_var,
2258 		zend_long optimization_level) {
2259 	uint32_t tmp = 0;
2260 	uint32_t t1_type = (t1 & MAY_BE_ANY) | (t1 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
2261 	uint32_t t2_type = (t2 & MAY_BE_ANY) | (t2 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
2262 
2263 	if (!(ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level)) {
2264 		/* Handle potentially overloaded operators.
2265 		 * This could be made more precise by checking the class type, if known. */
2266 		if ((t1_type & MAY_BE_OBJECT) || (t2_type & MAY_BE_OBJECT)) {
2267 			/* This is somewhat GMP specific. */
2268 			tmp |= MAY_BE_OBJECT | MAY_BE_FALSE | MAY_BE_RC1;
2269 		}
2270 	}
2271 
2272 	switch (opcode) {
2273 		case ZEND_ADD:
2274 			if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) {
2275 				if (result_var < 0 ||
2276 					!ssa->var_info[result_var].has_range ||
2277 				    ssa->var_info[result_var].range.underflow ||
2278 				    ssa->var_info[result_var].range.overflow) {
2279 					/* may overflow */
2280 					tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2281 				} else {
2282 					tmp |= MAY_BE_LONG;
2283 				}
2284 			} else if (t1_type == MAY_BE_DOUBLE || t2_type == MAY_BE_DOUBLE) {
2285 				tmp |= MAY_BE_DOUBLE;
2286 			} else if (t1_type == MAY_BE_ARRAY && t2_type == MAY_BE_ARRAY) {
2287 				tmp |= MAY_BE_ARRAY | MAY_BE_RC1;
2288 				tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2289 				tmp |= t2 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2290 			} else {
2291 				tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2292 				if ((t1_type & MAY_BE_ARRAY) && (t2_type & MAY_BE_ARRAY)) {
2293 					tmp |= MAY_BE_ARRAY | MAY_BE_RC1;
2294 					tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2295 					tmp |= t2 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2296 				}
2297 			}
2298 			break;
2299 		case ZEND_SUB:
2300 		case ZEND_MUL:
2301 			if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) {
2302 				if (result_var < 0 ||
2303 					!ssa->var_info[result_var].has_range ||
2304 				    ssa->var_info[result_var].range.underflow ||
2305 				    ssa->var_info[result_var].range.overflow) {
2306 					/* may overflow */
2307 					tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2308 				} else {
2309 					tmp |= MAY_BE_LONG;
2310 				}
2311 			} else if (t1_type == MAY_BE_DOUBLE || t2_type == MAY_BE_DOUBLE) {
2312 				tmp |= MAY_BE_DOUBLE;
2313 			} else {
2314 				tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2315 			}
2316 			break;
2317 		case ZEND_DIV:
2318 		case ZEND_POW:
2319 			if (t1_type == MAY_BE_DOUBLE || t2_type == MAY_BE_DOUBLE) {
2320 				tmp |= MAY_BE_DOUBLE;
2321 			} else {
2322 				tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2323 			}
2324 			/* Division by zero results in Inf/-Inf/Nan (double), so it doesn't need any special
2325 			 * handling */
2326 			break;
2327 		case ZEND_MOD:
2328 			tmp |= MAY_BE_LONG;
2329 			/* Division by zero results in an exception, so it doesn't need any special handling */
2330 			break;
2331 		case ZEND_BW_OR:
2332 		case ZEND_BW_AND:
2333 		case ZEND_BW_XOR:
2334 			if ((t1_type & MAY_BE_STRING) && (t2_type & MAY_BE_STRING)) {
2335 				tmp |= MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
2336 			}
2337 			if ((t1_type & ~MAY_BE_STRING) || (t2_type & ~MAY_BE_STRING)) {
2338 				tmp |= MAY_BE_LONG;
2339 			}
2340 			break;
2341 		case ZEND_SL:
2342 		case ZEND_SR:
2343 			tmp |= MAY_BE_LONG;
2344 			break;
2345 		case ZEND_CONCAT:
2346 		case ZEND_FAST_CONCAT:
2347 			/* TODO: +MAY_BE_OBJECT ??? */
2348 			tmp = MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
2349 			break;
2350 		EMPTY_SWITCH_DEFAULT_CASE()
2351 	}
2352 	return tmp;
2353 }
2354 
zend_convert_type_declaration_mask(uint32_t type_mask)2355 static uint32_t zend_convert_type_declaration_mask(uint32_t type_mask) {
2356 	uint32_t result_mask = type_mask & MAY_BE_ANY;
2357 	if (type_mask & MAY_BE_VOID) {
2358 		result_mask |= MAY_BE_NULL;
2359 	}
2360 	if (type_mask & MAY_BE_CALLABLE) {
2361 		result_mask |= MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
2362 	}
2363 	if (type_mask & MAY_BE_STATIC) {
2364 		result_mask |= MAY_BE_OBJECT;
2365 	}
2366 	if (type_mask & MAY_BE_ARRAY) {
2367 		result_mask |= MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
2368 	}
2369 	return result_mask;
2370 }
2371 
zend_convert_type(const zend_script * script,zend_type type,zend_class_entry ** pce)2372 static uint32_t zend_convert_type(const zend_script *script, zend_type type, zend_class_entry **pce)
2373 {
2374 	if (pce) {
2375 		*pce = NULL;
2376 	}
2377 
2378 	if (!ZEND_TYPE_IS_SET(type)) {
2379 		return MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_RC1|MAY_BE_RCN;
2380 	}
2381 
2382 	uint32_t tmp = zend_convert_type_declaration_mask(ZEND_TYPE_PURE_MASK(type));
2383 	if (ZEND_TYPE_IS_COMPLEX(type)) {
2384 		tmp |= MAY_BE_OBJECT;
2385 		if (pce) {
2386 			/* As we only have space to store one CE,
2387 			 * we use a plain object type for class unions. */
2388 			if (ZEND_TYPE_HAS_NAME(type)) {
2389 				zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(type));
2390 				// TODO: Pass through op_array.
2391 				*pce = zend_optimizer_get_class_entry(script, NULL, lcname);
2392 				zend_string_release_ex(lcname, 0);
2393 			}
2394 		}
2395 	}
2396 	if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2397 		tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2398 	}
2399 	return tmp;
2400 }
2401 
zend_fetch_arg_info_type(const zend_script * script,const zend_arg_info * arg_info,zend_class_entry ** pce)2402 ZEND_API uint32_t zend_fetch_arg_info_type(const zend_script *script, const zend_arg_info *arg_info, zend_class_entry **pce)
2403 {
2404 	return zend_convert_type(script, arg_info->type, pce);
2405 }
2406 
lookup_prop_info(const zend_class_entry * ce,zend_string * name,zend_class_entry * scope)2407 static const zend_property_info *lookup_prop_info(const zend_class_entry *ce, zend_string *name, zend_class_entry *scope) {
2408 	const zend_property_info *prop_info;
2409 
2410 	/* If the class is linked, reuse the precise runtime logic. */
2411 	if ((ce->ce_flags & ZEND_ACC_LINKED)
2412 	 && (!scope || (scope->ce_flags & ZEND_ACC_LINKED))) {
2413 		zend_class_entry *prev_scope = EG(fake_scope);
2414 		EG(fake_scope) = scope;
2415 		prop_info = zend_get_property_info(ce, name, 1);
2416 		EG(fake_scope) = prev_scope;
2417 		if (prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO) {
2418 			return prop_info;
2419 		}
2420 		return NULL;
2421 	}
2422 
2423 	/* Otherwise, handle only some safe cases */
2424 	prop_info = zend_hash_find_ptr(&ce->properties_info, name);
2425 	if (prop_info &&
2426 		((prop_info->ce == scope) ||
2427 		 (!scope && (prop_info->flags & ZEND_ACC_PUBLIC)))
2428 	) {
2429 		return prop_info;
2430 	}
2431 	return NULL;
2432 }
2433 
zend_fetch_prop_info(const zend_op_array * op_array,zend_ssa * ssa,const zend_op * opline,const zend_ssa_op * ssa_op)2434 static const zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op)
2435 {
2436 	const zend_property_info *prop_info = NULL;
2437 	if (opline->op2_type == IS_CONST) {
2438 		const zend_class_entry *ce = NULL;
2439 
2440 		if (opline->op1_type == IS_UNUSED && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
2441 			ce = op_array->scope;
2442 		} else if (ssa_op->op1_use >= 0) {
2443 			ce = ssa->var_info[ssa_op->op1_use].ce;
2444 		}
2445 		if (ce) {
2446 			prop_info = lookup_prop_info(ce,
2447 				Z_STR_P(CRT_CONSTANT(opline->op2)),
2448 				op_array->scope);
2449 			if (prop_info && (prop_info->flags & ZEND_ACC_STATIC)) {
2450 				prop_info = NULL;
2451 			}
2452 		}
2453 	}
2454 	return prop_info;
2455 }
2456 
zend_fetch_static_prop_info(const zend_script * script,const zend_op_array * op_array,const zend_ssa * ssa,const zend_op * opline)2457 static const zend_property_info *zend_fetch_static_prop_info(const zend_script *script, const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline)
2458 {
2459 	const zend_property_info *prop_info = NULL;
2460 	if (opline->op1_type == IS_CONST) {
2461 		zend_class_entry *ce = NULL;
2462 		if (opline->op2_type == IS_UNUSED) {
2463 			int fetch_type = opline->op2.num & ZEND_FETCH_CLASS_MASK;
2464 			switch (fetch_type) {
2465 				case ZEND_FETCH_CLASS_SELF:
2466 				case ZEND_FETCH_CLASS_STATIC:
2467 					/* We enforce that static property types cannot change during inheritance, so
2468 					 * handling static the same way as self here is legal. */
2469 					ce = op_array->scope;
2470 					break;
2471 				case ZEND_FETCH_CLASS_PARENT:
2472 					if (op_array->scope && (op_array->scope->ce_flags & ZEND_ACC_LINKED)) {
2473 						ce = op_array->scope->parent;
2474 					}
2475 					break;
2476 			}
2477 		} else if (opline->op2_type == IS_CONST) {
2478 			zval *zv = CRT_CONSTANT(opline->op2);
2479 			ce = zend_optimizer_get_class_entry(script, op_array, Z_STR_P(zv + 1));
2480 		}
2481 
2482 		if (ce) {
2483 			zval *zv = CRT_CONSTANT(opline->op1);
2484 			prop_info = lookup_prop_info(ce, Z_STR_P(zv), op_array->scope);
2485 			if (prop_info && !(prop_info->flags & ZEND_ACC_STATIC)) {
2486 				prop_info = NULL;
2487 			}
2488 		}
2489 	}
2490 	return prop_info;
2491 }
2492 
zend_fetch_prop_type(const zend_script * script,const zend_property_info * prop_info,zend_class_entry ** pce)2493 static uint32_t zend_fetch_prop_type(const zend_script *script, const zend_property_info *prop_info, zend_class_entry **pce)
2494 {
2495 	if (!prop_info) {
2496 		if (pce) {
2497 			*pce = NULL;
2498 		}
2499 		return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN;
2500 	}
2501 
2502 	return zend_convert_type(script, prop_info->type, pce);
2503 }
2504 
result_may_be_separated(zend_ssa * ssa,zend_ssa_op * ssa_op)2505 static bool result_may_be_separated(zend_ssa *ssa, zend_ssa_op *ssa_op)
2506 {
2507 	int tmp_var = ssa_op->result_def;
2508 
2509 	if (ssa->vars[tmp_var].use_chain >= 0
2510 	 && !ssa->vars[tmp_var].phi_use_chain) {
2511 		zend_ssa_op *use_op = &ssa->ops[ssa->vars[tmp_var].use_chain];
2512 
2513 		/* TODO: analyze instructions between ssa_op and use_op */
2514 		if (use_op == ssa_op + 1) {
2515 			if ((use_op->op1_use == tmp_var && use_op->op1_use_chain < 0)
2516 			 || (use_op->op2_use == tmp_var && use_op->op2_use_chain < 0)) {
2517 				return 0;
2518 			}
2519 		}
2520 	}
2521 	return 1;
2522 }
2523 
_zend_update_type_info(const zend_op_array * op_array,zend_ssa * ssa,const zend_script * script,zend_bitset worklist,const zend_op * opline,zend_ssa_op * ssa_op,const zend_op ** ssa_opcodes,zend_long optimization_level,bool update_worklist)2524 static zend_always_inline zend_result _zend_update_type_info(
2525 			const zend_op_array *op_array,
2526 			zend_ssa            *ssa,
2527 			const zend_script   *script,
2528 			zend_bitset          worklist,
2529 			const zend_op       *opline,
2530 			zend_ssa_op         *ssa_op,
2531 			const zend_op      **ssa_opcodes,
2532 			zend_long            optimization_level,
2533 			bool            update_worklist)
2534 {
2535 	uint32_t t1, t2;
2536 	uint32_t tmp, orig;
2537 	zend_ssa_var *ssa_vars = ssa->vars;
2538 	zend_ssa_var_info *ssa_var_info = ssa->var_info;
2539 	zend_class_entry *ce;
2540 	int j;
2541 
2542 	if (opline->opcode == ZEND_OP_DATA) {
2543 		opline--;
2544 		ssa_op--;
2545 	}
2546 
2547 	t1 = OP1_INFO();
2548 	t2 = OP2_INFO();
2549 
2550 	/* If one of the operands cannot have any type, this means the operand derives from
2551 	 * unreachable code. Propagate the empty result early, so that that the following
2552 	 * code may assume that operands have at least one type. */
2553 	if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
2554 	 || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
2555 	 || (ssa_op->result_use >= 0 && !(RES_USE_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS)))
2556 	 || ((opline->opcode == ZEND_ASSIGN_DIM_OP
2557 	   || opline->opcode == ZEND_ASSIGN_OBJ_OP
2558 	   || opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP
2559 	   || opline->opcode == ZEND_ASSIGN_DIM
2560 	   || opline->opcode == ZEND_ASSIGN_OBJ)
2561 	    && !(OP1_DATA_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS)) /*&& 0*/)) {
2562 		tmp = 0;
2563 		if (ssa_op->result_def >= 0 && !(ssa_var_info[ssa_op->result_def].type & MAY_BE_REF)) {
2564 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2565 		}
2566 		if (ssa_op->op1_def >= 0 && !(ssa_var_info[ssa_op->op1_def].type & MAY_BE_REF)) {
2567 			UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2568 		}
2569 		if (ssa_op->op2_def >= 0 && !(ssa_var_info[ssa_op->op2_def].type & MAY_BE_REF)) {
2570 			UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
2571 		}
2572 		if (opline->opcode == ZEND_ASSIGN_DIM_OP
2573 		 || opline->opcode == ZEND_ASSIGN_OBJ_OP
2574 		 || opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP
2575 		 || opline->opcode == ZEND_ASSIGN_DIM
2576 		 || opline->opcode == ZEND_ASSIGN_OBJ) {
2577 			if ((ssa_op+1)->op1_def >= 0 && !(ssa_var_info[(ssa_op+1)->op1_def].type & MAY_BE_REF)) {
2578 				UPDATE_SSA_TYPE(tmp, (ssa_op+1)->op1_def);
2579 			}
2580 		}
2581 		return SUCCESS;
2582 	}
2583 
2584 	switch (opline->opcode) {
2585 		case ZEND_ADD:
2586 		case ZEND_SUB:
2587 		case ZEND_MUL:
2588 		case ZEND_DIV:
2589 		case ZEND_POW:
2590 		case ZEND_MOD:
2591 		case ZEND_BW_OR:
2592 		case ZEND_BW_AND:
2593 		case ZEND_BW_XOR:
2594 		case ZEND_SL:
2595 		case ZEND_SR:
2596 		case ZEND_CONCAT:
2597 			tmp = binary_op_result_type(ssa, opline->opcode, t1, t2, ssa_op->result_def, optimization_level);
2598 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2599 			break;
2600 		case ZEND_BW_NOT:
2601 			tmp = 0;
2602 			if (t1 & MAY_BE_STRING) {
2603 				tmp |= MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
2604 			}
2605 			if (t1 & (MAY_BE_ANY-MAY_BE_STRING)) {
2606 				tmp |= MAY_BE_LONG;
2607 			}
2608 			if (!(ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level)) {
2609 				if (t1 & MAY_BE_OBJECT) {
2610 					/* Potentially overloaded operator. */
2611 					tmp |= MAY_BE_OBJECT | MAY_BE_RC1;
2612 				}
2613 			}
2614 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2615 			break;
2616 		case ZEND_BEGIN_SILENCE:
2617 			UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def);
2618 			break;
2619 		case ZEND_BOOL_NOT:
2620 		case ZEND_BOOL_XOR:
2621 		case ZEND_IS_IDENTICAL:
2622 		case ZEND_IS_NOT_IDENTICAL:
2623 		case ZEND_IS_EQUAL:
2624 		case ZEND_IS_NOT_EQUAL:
2625 		case ZEND_IS_SMALLER:
2626 		case ZEND_IS_SMALLER_OR_EQUAL:
2627 		case ZEND_INSTANCEOF:
2628 		case ZEND_JMPZ_EX:
2629 		case ZEND_JMPNZ_EX:
2630 		case ZEND_CASE:
2631 		case ZEND_CASE_STRICT:
2632 		case ZEND_BOOL:
2633 		case ZEND_ISSET_ISEMPTY_CV:
2634 		case ZEND_ISSET_ISEMPTY_VAR:
2635 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
2636 		case ZEND_ISSET_ISEMPTY_PROP_OBJ:
2637 		case ZEND_ISSET_ISEMPTY_STATIC_PROP:
2638 		case ZEND_ASSERT_CHECK:
2639 		case ZEND_IN_ARRAY:
2640 		case ZEND_ARRAY_KEY_EXISTS:
2641 			UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_op->result_def);
2642 			break;
2643 		case ZEND_CAST:
2644 			if (ssa_op->op1_def >= 0) {
2645 				tmp = t1;
2646 				if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) &&
2647 				    (opline->extended_value == IS_ARRAY ||
2648 				     opline->extended_value == IS_OBJECT)) {
2649 					tmp |= MAY_BE_RCN;
2650 				} else if ((t1 & MAY_BE_STRING) &&
2651 				    opline->extended_value == IS_STRING) {
2652 					tmp |= MAY_BE_RCN;
2653 				}
2654 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2655 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2656 			}
2657 			tmp = 1 << opline->extended_value;
2658 			if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2659 				if ((tmp & MAY_BE_ANY) == (t1 & MAY_BE_ANY)) {
2660 					tmp |= (t1 & MAY_BE_RC1) | MAY_BE_RCN;
2661 				} else if ((opline->extended_value == IS_ARRAY ||
2662 							opline->extended_value == IS_OBJECT) &&
2663 						   (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
2664 						tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2665 				} else if (opline->extended_value == IS_STRING &&
2666 						   (t1 & (MAY_BE_STRING|MAY_BE_OBJECT))) {
2667 					tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2668 				} else {
2669 					tmp |= MAY_BE_RC1;
2670 					if (opline->extended_value == IS_ARRAY
2671 					 && (t1 & (MAY_BE_UNDEF|MAY_BE_NULL))) {
2672 						tmp |= MAY_BE_RCN;
2673 					}
2674 				}
2675 			}
2676 			if (opline->extended_value == IS_ARRAY) {
2677 				if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL)) {
2678 					tmp |= MAY_BE_ARRAY_EMPTY;
2679 				}
2680 				if (t1 & MAY_BE_ARRAY) {
2681 					tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF);
2682 				}
2683 				if (t1 & MAY_BE_OBJECT) {
2684 					tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2685 				} else if (t1 & (MAY_BE_ANY - MAY_BE_NULL)) {
2686 					tmp |= ((t1 & (MAY_BE_ANY - MAY_BE_NULL)) << MAY_BE_ARRAY_SHIFT) | ((t1 & MAY_BE_NULL) ? MAY_BE_ARRAY_KEY_LONG : MAY_BE_ARRAY_PACKED);
2687 				}
2688 			}
2689 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2690 			break;
2691 		case ZEND_QM_ASSIGN:
2692 		case ZEND_JMP_SET:
2693 		case ZEND_COALESCE:
2694 		case ZEND_COPY_TMP:
2695 			if (ssa_op->op1_def >= 0) {
2696 				tmp = t1;
2697 				if (t1 & (MAY_BE_RC1|MAY_BE_REF)) {
2698 					tmp |= MAY_BE_RCN;
2699 				}
2700 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2701 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2702 			}
2703 			tmp = t1 & ~MAY_BE_UNDEF;
2704 			if (opline->opcode != ZEND_COPY_TMP || opline->op1_type != IS_VAR) {
2705 				tmp &= ~MAY_BE_REF;
2706 			}
2707 			if (t1 & MAY_BE_UNDEF) {
2708 				tmp |= MAY_BE_NULL;
2709 			}
2710 			if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2711 				tmp |= (t1 & (MAY_BE_RC1|MAY_BE_RCN));
2712 				if (opline->opcode == ZEND_COPY_TMP || opline->op1_type == IS_CV) {
2713 					tmp |= MAY_BE_RCN;
2714 				}
2715 			}
2716 			if (opline->opcode == ZEND_COALESCE || opline->opcode == ZEND_JMP_SET) {
2717 				/* COALESCE and JMP_SET result can't be null */
2718 				tmp &= ~MAY_BE_NULL;
2719 				if (opline->opcode == ZEND_JMP_SET) {
2720 					/* JMP_SET result can't be false either */
2721 					tmp &= ~MAY_BE_FALSE;
2722 				}
2723 			}
2724 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2725 			COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
2726 			break;
2727 		case ZEND_JMP_NULL:
2728 		{
2729 			uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
2730 			if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR) {
2731 				tmp = MAY_BE_NULL;
2732 			} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
2733 				tmp = MAY_BE_FALSE;
2734 			} else {
2735 				ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
2736 				tmp = MAY_BE_TRUE;
2737 			}
2738 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2739 			break;
2740 		}
2741 		case ZEND_ASSIGN_OP:
2742 		case ZEND_ASSIGN_DIM_OP:
2743 		case ZEND_ASSIGN_OBJ_OP:
2744 		case ZEND_ASSIGN_STATIC_PROP_OP:
2745 		{
2746 			const zend_property_info *prop_info = NULL;
2747 			orig = 0;
2748 			tmp = 0;
2749 			if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
2750 				prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
2751 				orig = t1;
2752 				t1 = zend_fetch_prop_type(script, prop_info, NULL);
2753 				t2 = OP1_DATA_INFO();
2754 			} else if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
2755 				if (t1 & MAY_BE_ARRAY_OF_REF) {
2756 			        tmp |= MAY_BE_REF;
2757 				}
2758 				orig = t1;
2759 				t1 = zend_array_element_type(t1, opline->op1_type, 1, 0);
2760 				t2 = OP1_DATA_INFO();
2761 			} else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
2762 				prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline);
2763 				t1 = zend_fetch_prop_type(script, prop_info, NULL);
2764 				t2 = OP1_DATA_INFO();
2765 			} else {
2766 				if (t1 & MAY_BE_REF) {
2767 			        tmp |= MAY_BE_REF;
2768 				}
2769 			}
2770 
2771 			tmp |= binary_op_result_type(
2772 				ssa, opline->extended_value, t1, t2,
2773 				opline->opcode == ZEND_ASSIGN_OP ? ssa_op->op1_def : -1, optimization_level);
2774 			if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY)) {
2775 				tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2776 			}
2777 			if (tmp & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2778 				tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2779 			}
2780 
2781 			if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
2782 				if (opline->op1_type == IS_CV) {
2783 					orig = assign_dim_result_type(orig, OP2_INFO(), tmp, opline->op2_type);
2784 					UPDATE_SSA_TYPE(orig, ssa_op->op1_def);
2785 					COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2786 				}
2787 			} else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
2788 				if (opline->op1_type == IS_CV) {
2789 					orig = (orig & (MAY_BE_REF|MAY_BE_OBJECT))|MAY_BE_RC1|MAY_BE_RCN;
2790 					UPDATE_SSA_TYPE(orig, ssa_op->op1_def);
2791 					COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2792 				}
2793 			} else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
2794 				/* Nothing to do */
2795 			} else {
2796 				if (opline->opcode == ZEND_ASSIGN_OP && ssa_op->result_def >= 0 && (tmp & MAY_BE_RC1)) {
2797 					tmp |= MAY_BE_RCN;
2798 				}
2799 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2800 			}
2801 			if (ssa_op->result_def >= 0) {
2802 				ce = NULL;
2803 				if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
2804 					if (opline->op2_type == IS_UNUSED) {
2805 						/* When appending to an array and the LONG_MAX key is already used
2806 						 * null will be returned. */
2807 						tmp |= MAY_BE_NULL;
2808 					}
2809 					if (t2 & (MAY_BE_ARRAY | MAY_BE_OBJECT)) {
2810 						/* Arrays and objects cannot be used as keys. */
2811 						tmp |= MAY_BE_NULL;
2812 					}
2813 					if (t1 & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY))) {
2814 						/* null and false are implicitly converted to array, anything else
2815 						 * results in a null return value. */
2816 						tmp |= MAY_BE_NULL;
2817 					}
2818 					if (tmp & MAY_BE_REF) {
2819 						/* Typed reference may cause auto conversion */
2820 						tmp |= MAY_BE_ANY;
2821 					}
2822 				} else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
2823 					/* The return value must also satisfy the property type */
2824 					if (prop_info) {
2825 						t1 = zend_fetch_prop_type(script, prop_info, &ce);
2826 						if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_LONG
2827 						 && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_DOUBLE) {
2828 							/* DOUBLE may be auto-converted to LONG */
2829 							tmp |= MAY_BE_LONG;
2830 							tmp &= ~MAY_BE_DOUBLE;
2831 						} else if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING)) == MAY_BE_STRING
2832 						 && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
2833 							/* LONG/DOUBLE may be auto-converted to STRING */
2834 							tmp |= MAY_BE_STRING;
2835 							tmp &= ~(MAY_BE_LONG|MAY_BE_DOUBLE);
2836 						}
2837 						tmp &= t1;
2838 					} else {
2839 						tmp |= MAY_BE_LONG | MAY_BE_STRING;
2840 					}
2841 				} else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
2842 					/* The return value must also satisfy the property type */
2843 					if (prop_info) {
2844 						t1 = zend_fetch_prop_type(script, prop_info, &ce);
2845 						if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_LONG
2846 						 && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_DOUBLE) {
2847 							/* DOUBLE may be auto-converted to LONG */
2848 							tmp |= MAY_BE_LONG;
2849 							tmp &= ~MAY_BE_DOUBLE;
2850 						} else if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING)) == MAY_BE_STRING
2851 						 && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
2852 							/* LONG/DOUBLE may be auto-converted to STRING */
2853 							tmp |= MAY_BE_STRING;
2854 							tmp &= ~(MAY_BE_LONG|MAY_BE_DOUBLE);
2855 						}
2856 						tmp &= t1;
2857 					} else {
2858 						tmp |= MAY_BE_LONG | MAY_BE_STRING;
2859 					}
2860 				} else {
2861 					if (tmp & MAY_BE_REF) {
2862 						/* Typed reference may cause auto conversion */
2863 						tmp |= MAY_BE_ANY;
2864 					}
2865 				}
2866 				tmp &= ~MAY_BE_REF;
2867 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2868 				if (ce) {
2869 					UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
2870 				}
2871 			}
2872 			break;
2873 		}
2874 		case ZEND_PRE_INC:
2875 		case ZEND_PRE_DEC:
2876 			tmp = 0;
2877 			if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2878 				tmp |= MAY_BE_RC1;
2879 				if (ssa_op->result_def >= 0) {
2880 					tmp |= MAY_BE_RCN;
2881 				}
2882 			}
2883 			if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
2884 				if (!ssa_var_info[ssa_op->op1_use].has_range ||
2885 				    (opline->opcode == ZEND_PRE_DEC &&
2886 				     (ssa_var_info[ssa_op->op1_use].range.underflow ||
2887 				      ssa_var_info[ssa_op->op1_use].range.min == ZEND_LONG_MIN)) ||
2888 				     (opline->opcode == ZEND_PRE_INC &&
2889 				      (ssa_var_info[ssa_op->op1_use].range.overflow ||
2890 				       ssa_var_info[ssa_op->op1_use].range.max == ZEND_LONG_MAX))) {
2891 					/* may overflow */
2892 					tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2893 				} else {
2894 					tmp |= MAY_BE_LONG;
2895 				}
2896 			} else {
2897 				if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
2898 					if (opline->opcode == ZEND_PRE_INC) {
2899 						tmp |= MAY_BE_LONG;
2900 					} else {
2901 						tmp |= MAY_BE_NULL;
2902 					}
2903 				}
2904 				if (t1 & MAY_BE_LONG) {
2905 					tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2906 				}
2907 				if (t1 & MAY_BE_DOUBLE) {
2908 					tmp |= MAY_BE_DOUBLE;
2909 				}
2910 				if (t1 & MAY_BE_STRING) {
2911 					tmp |= MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE;
2912 				}
2913 				tmp |= t1 & (MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT);
2914 			}
2915 			if (ssa_op->result_def >= 0) {
2916 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2917 			}
2918 			if (ssa_op->op1_def >= 0) {
2919 				if (t1 & MAY_BE_REF) {
2920 					tmp |= MAY_BE_REF;
2921 				}
2922 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2923 			}
2924 			break;
2925 		case ZEND_POST_INC:
2926 		case ZEND_POST_DEC:
2927 			if (ssa_op->result_def >= 0) {
2928 				tmp = 0;
2929 				if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2930 					tmp |= MAY_BE_RC1|MAY_BE_RCN;
2931 				}
2932 				tmp |= t1 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RCN);
2933 				if (t1 & MAY_BE_UNDEF) {
2934 					tmp |= MAY_BE_NULL;
2935 				}
2936 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2937 			}
2938 			tmp = 0;
2939 			if (t1 & MAY_BE_REF) {
2940 				tmp |= MAY_BE_REF;
2941 			}
2942 			if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2943 				tmp |= MAY_BE_RC1;
2944 			}
2945 			if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
2946 				if (!ssa_var_info[ssa_op->op1_use].has_range ||
2947 				     (opline->opcode == ZEND_POST_DEC &&
2948 				      (ssa_var_info[ssa_op->op1_use].range.underflow ||
2949 				       ssa_var_info[ssa_op->op1_use].range.min == ZEND_LONG_MIN)) ||
2950 				      (opline->opcode == ZEND_POST_INC &&
2951 				       (ssa_var_info[ssa_op->op1_use].range.overflow ||
2952 				        ssa_var_info[ssa_op->op1_use].range.max == ZEND_LONG_MAX))) {
2953 					/* may overflow */
2954 					tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2955 				} else {
2956 					tmp |= MAY_BE_LONG;
2957 				}
2958 			} else {
2959 				if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
2960 					if (opline->opcode == ZEND_POST_INC) {
2961 						tmp |= MAY_BE_LONG;
2962 					} else {
2963 						tmp |= MAY_BE_NULL;
2964 					}
2965 				}
2966 				if (t1 & MAY_BE_LONG) {
2967 					tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2968 				}
2969 				if (t1 & MAY_BE_DOUBLE) {
2970 					tmp |= MAY_BE_DOUBLE;
2971 				}
2972 				if (t1 & MAY_BE_STRING) {
2973 					tmp |= MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE;
2974 				}
2975 				tmp |= t1 & (MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY);
2976 			}
2977 			if (ssa_op->op1_def >= 0) {
2978 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2979 			}
2980 			break;
2981 		case ZEND_ASSIGN_DIM:
2982 			if (opline->op1_type == IS_CV) {
2983 				tmp = assign_dim_result_type(t1, t2, OP1_DATA_INFO(), opline->op2_type);
2984 				tmp |= ssa->var_info[ssa_op->op1_def].type & (MAY_BE_ARRAY_PACKED|MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2985 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2986 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2987 			}
2988 			if (ssa_op->result_def >= 0) {
2989 				tmp = 0;
2990 				if (t1 & MAY_BE_STRING) {
2991 					tmp |= MAY_BE_STRING | MAY_BE_NULL;
2992 				}
2993 				if (t1 & MAY_BE_OBJECT) {
2994 					tmp |= (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF);
2995 				}
2996 				if (t1 & (MAY_BE_ARRAY|MAY_BE_FALSE|MAY_BE_NULL|MAY_BE_UNDEF)) {
2997 					tmp |= (OP1_DATA_INFO() & (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF));
2998 
2999 					if (OP1_DATA_INFO() & MAY_BE_UNDEF) {
3000 						tmp |= MAY_BE_NULL;
3001 					}
3002 					if (t1 & MAY_BE_ARRAY_OF_REF) {
3003 						/* A scalar type conversion may occur when assigning to a typed reference. */
3004 						tmp |= MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING;
3005 					}
3006 				}
3007 				if (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
3008 					tmp |= MAY_BE_NULL;
3009 				}
3010 				tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3011 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3012 			}
3013 			if ((ssa_op+1)->op1_def >= 0) {
3014 				opline++;
3015 				ssa_op++;
3016 				tmp = OP1_INFO();
3017 				if (tmp & (MAY_BE_ANY | MAY_BE_REF)) {
3018 					if (tmp & MAY_BE_RC1) {
3019 						tmp |= MAY_BE_RCN;
3020 					}
3021 				}
3022 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3023 			}
3024 			break;
3025 		case ZEND_ASSIGN_OBJ:
3026 			if (opline->op1_type == IS_CV) {
3027 				tmp = (t1 & (MAY_BE_REF|MAY_BE_OBJECT))|MAY_BE_RC1|MAY_BE_RCN;
3028 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3029 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3030 			}
3031 			if (ssa_op->result_def >= 0) {
3032 				// TODO: If there is no __set we might do better
3033 				tmp = zend_fetch_prop_type(script,
3034 					zend_fetch_prop_info(op_array, ssa, opline, ssa_op), &ce);
3035 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3036 				if (ce) {
3037 					UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3038 				}
3039 			}
3040 			if ((ssa_op+1)->op1_def >= 0) {
3041 				opline++;
3042 				ssa_op++;
3043 				tmp = OP1_INFO();
3044 				if (tmp & MAY_BE_RC1) {
3045 					tmp |= MAY_BE_RCN;
3046 				}
3047 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3048 			}
3049 			break;
3050 		case ZEND_ASSIGN_STATIC_PROP:
3051 			if (ssa_op->result_def >= 0) {
3052 				tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN;
3053 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3054 			}
3055 			if ((ssa_op+1)->op1_def >= 0) {
3056 				opline++;
3057 				ssa_op++;
3058 				tmp = OP1_INFO();
3059 				if (tmp & MAY_BE_RC1) {
3060 					tmp |= MAY_BE_RCN;
3061 				}
3062 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3063 			}
3064 			break;
3065 		case ZEND_PRE_INC_OBJ:
3066 		case ZEND_PRE_DEC_OBJ:
3067 		case ZEND_POST_INC_OBJ:
3068 		case ZEND_POST_DEC_OBJ:
3069 			if (opline->op1_type == IS_CV) {
3070 				tmp = (t1 & (MAY_BE_REF|MAY_BE_OBJECT))|MAY_BE_RC1|MAY_BE_RCN;
3071 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3072 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3073 			}
3074 			if (ssa_op->result_def >= 0) {
3075 				// TODO: ???
3076 				tmp = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3077 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3078 			}
3079 			break;
3080 		case ZEND_ASSIGN:
3081 			if (ssa_op->op2_def >= 0) {
3082 				tmp = t2;
3083 				if (tmp & MAY_BE_RC1) {
3084 					tmp |= MAY_BE_RCN;
3085 				}
3086 				UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3087 			}
3088 			tmp = t2 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
3089 			if (t2 & MAY_BE_UNDEF) {
3090 				tmp |= MAY_BE_NULL;
3091 			}
3092 			if (t1 & MAY_BE_REF) {
3093 				tmp |= MAY_BE_REF;
3094 			}
3095 			if (t2 & MAY_BE_REF) {
3096 				tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3097 			} else if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
3098 				tmp |= t2 & (MAY_BE_RC1|MAY_BE_RCN);
3099 			} else if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) {
3100 				tmp |= MAY_BE_RCN;
3101 			}
3102 			if (RETURN_VALUE_USED(opline) && (tmp & MAY_BE_RC1)) {
3103 				tmp |= MAY_BE_RCN;
3104 			}
3105 			if (ssa_op->op1_def >= 0) {
3106 				if (ssa_var_info[ssa_op->op1_def].use_as_double) {
3107 					tmp &= ~MAY_BE_LONG;
3108 					tmp |= MAY_BE_DOUBLE;
3109 				}
3110 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3111 				COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->op1_def);
3112 			}
3113 			if (ssa_op->result_def >= 0) {
3114 				if (tmp & MAY_BE_REF) {
3115 					/* A scalar type conversion may occur when assigning to a typed reference. */
3116 					tmp &= ~MAY_BE_REF;
3117 					tmp |= MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN;
3118 				}
3119 				if ((tmp & (MAY_BE_RC1|MAY_BE_RCN)) == MAY_BE_RCN) {
3120 					/* refcount may be indirectly decremented. Make an exception if the result is used in the next instruction */
3121 					if (!ssa_opcodes) {
3122 						if (ssa->vars[ssa_op->result_def].use_chain < 0
3123 						 || opline + 1 != op_array->opcodes + ssa->vars[ssa_op->result_def].use_chain) {
3124 							tmp |= MAY_BE_RC1;
3125 					    }
3126 					} else {
3127 						if (ssa->vars[ssa_op->result_def].use_chain < 0
3128 						 || opline + 1 != ssa_opcodes[ssa->vars[ssa_op->result_def].use_chain]) {
3129 							tmp |= MAY_BE_RC1;
3130 					    }
3131 					}
3132 				}
3133 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3134 				COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->result_def);
3135 			}
3136 			break;
3137 		case ZEND_ASSIGN_REF:
3138 // TODO: ???
3139 			if (opline->op2_type == IS_CV) {
3140 				tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3141 				if (t2 & MAY_BE_UNDEF) {
3142 					tmp |= MAY_BE_NULL;
3143 				}
3144 				UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3145 			}
3146 			if (opline->op2_type == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION) {
3147 				tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
3148 			} else {
3149 				tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3150 			}
3151 			if (t2 & MAY_BE_UNDEF) {
3152 				tmp |= MAY_BE_NULL;
3153 			}
3154 			UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3155 			if (ssa_op->result_def >= 0) {
3156 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3157 			}
3158 			break;
3159 		case ZEND_ASSIGN_OBJ_REF:
3160 			if (opline->op1_type == IS_CV) {
3161 				tmp = t1;
3162 				if (tmp & MAY_BE_OBJECT) {
3163 					tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3164 				}
3165 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3166 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3167 			}
3168 
3169 			t2 = OP1_DATA_INFO();
3170 			if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION)) {
3171 				tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
3172 			} else {
3173 				tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3174 			}
3175 			if (t2 & MAY_BE_UNDEF) {
3176 				tmp |= MAY_BE_NULL;
3177 			}
3178 			if (ssa_op->result_def >= 0) {
3179 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3180 			}
3181 			if ((opline+1)->op1_type == IS_CV) {
3182 				opline++;
3183 				ssa_op++;
3184 				tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3185 				if (t2 & MAY_BE_UNDEF) {
3186 					tmp |= MAY_BE_NULL;
3187 				}
3188 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3189 			}
3190 			break;
3191 		case ZEND_ASSIGN_STATIC_PROP_REF:
3192 			if (ssa_op->result_def >= 0) {
3193 				UPDATE_SSA_TYPE(MAY_BE_REF, ssa_op->result_def);
3194 			}
3195 			if ((opline+1)->op1_type == IS_CV) {
3196 				opline++;
3197 				ssa_op++;
3198 				UPDATE_SSA_TYPE(MAY_BE_REF, ssa_op->op1_def);
3199 			}
3200 			break;
3201 		case ZEND_BIND_GLOBAL:
3202 			tmp = MAY_BE_REF | MAY_BE_ANY
3203 				| MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3204 			UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3205 			break;
3206 		case ZEND_BIND_STATIC:
3207 			tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
3208 				| ((opline->extended_value & ZEND_BIND_REF) ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN));
3209 			if (opline->extended_value & ZEND_BIND_IMPLICIT) {
3210 				tmp |= MAY_BE_UNDEF;
3211 			}
3212 			UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3213 			break;
3214 		case ZEND_BIND_INIT_STATIC_OR_JMP:
3215 			tmp = MAY_BE_UNDEF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_REF;
3216 			UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3217 			break;
3218 		case ZEND_SEND_VAR:
3219 			if (ssa_op->op1_def >= 0) {
3220 				tmp = t1;
3221 				if (t1 & (MAY_BE_RC1|MAY_BE_REF)) {
3222 					tmp |= MAY_BE_RCN;
3223 				}
3224 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3225 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3226 			}
3227 			break;
3228 		case ZEND_BIND_LEXICAL:
3229 			if (ssa_op->op2_def >= 0) {
3230 				if (opline->extended_value & ZEND_BIND_REF) {
3231 					tmp = t2 | MAY_BE_REF;
3232 				} else {
3233 					tmp = t2 & ~(MAY_BE_RC1|MAY_BE_RCN);
3234 					if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) {
3235 						tmp |= MAY_BE_RCN;
3236 					}
3237 				}
3238 				UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3239 				COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->op2_def);
3240 			}
3241 			break;
3242 		case ZEND_YIELD:
3243 			if (ssa_op->op1_def >= 0) {
3244 				if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
3245 					tmp = t1 | MAY_BE_REF;
3246 				} else {
3247 					tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN);
3248 					if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
3249 						tmp |= MAY_BE_RCN;
3250 					}
3251 				}
3252 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3253 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3254 			}
3255 			if (ssa_op->result_def >= 0) {
3256 				tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
3257 					| MAY_BE_RC1 | MAY_BE_RCN;
3258 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3259 			}
3260 			break;
3261 		case ZEND_SEND_VAR_EX:
3262 		case ZEND_SEND_FUNC_ARG:
3263 			if (ssa_op->op1_def >= 0) {
3264 				tmp = (t1 & MAY_BE_UNDEF)|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3265 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3266 			}
3267 			break;
3268 		case ZEND_SEND_REF:
3269 			if (ssa_op->op1_def >= 0) {
3270 				tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3271 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3272 			}
3273 			break;
3274 		case ZEND_SEND_UNPACK:
3275 			if (ssa_op->op1_def >= 0) {
3276 				tmp = t1;
3277 				if (t1 & MAY_BE_ARRAY) {
3278 					tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3279 					if (t1 & MAY_BE_ARRAY_OF_ANY) {
3280 						/* SEND_UNPACK may acquire references into the array */
3281 						tmp |= MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3282 					}
3283 				}
3284 				if (t1 & MAY_BE_OBJECT) {
3285 					tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3286 				}
3287 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3288 			}
3289 			break;
3290 		case ZEND_FAST_CONCAT:
3291 		case ZEND_ROPE_INIT:
3292 		case ZEND_ROPE_ADD:
3293 		case ZEND_ROPE_END:
3294 			UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_op->result_def);
3295 			break;
3296 		case ZEND_RECV:
3297 		case ZEND_RECV_INIT:
3298 		case ZEND_RECV_VARIADIC:
3299 		{
3300 			/* Typehinting */
3301 			zend_arg_info *arg_info = &op_array->arg_info[opline->op1.num-1];
3302 
3303 			ce = NULL;
3304 			tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
3305 			if (ZEND_ARG_SEND_MODE(arg_info)) {
3306 				tmp |= MAY_BE_REF;
3307 				ce = NULL;
3308 			}
3309 
3310 			if (opline->opcode == ZEND_RECV_VARIADIC) {
3311 				uint32_t elem_type = tmp & MAY_BE_REF
3312 					? MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF
3313 					: (tmp & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
3314 				tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|elem_type;
3315 				ce = NULL;
3316 			}
3317 
3318 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3319 			if (ce) {
3320 				UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3321 			} else {
3322 				UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3323 			}
3324 			break;
3325 		}
3326 		case ZEND_DECLARE_ANON_CLASS:
3327 			UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_op->result_def);
3328 			if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT(opline->op1)))) != NULL) {
3329 				UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def);
3330 			}
3331 			break;
3332 		case ZEND_FETCH_CLASS:
3333 			UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_op->result_def);
3334 			if (opline->op2_type == IS_UNUSED) {
3335 				switch (opline->op1.num & ZEND_FETCH_CLASS_MASK) {
3336 					case ZEND_FETCH_CLASS_SELF:
3337 						if (op_array->scope) {
3338 							UPDATE_SSA_OBJ_TYPE(op_array->scope, 0, ssa_op->result_def);
3339 						} else {
3340 							UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3341 						}
3342 						break;
3343 					case ZEND_FETCH_CLASS_PARENT:
3344 						if (op_array->scope && op_array->scope->parent && (op_array->scope->ce_flags & ZEND_ACC_LINKED)) {
3345 							UPDATE_SSA_OBJ_TYPE(op_array->scope->parent, 0, ssa_op->result_def);
3346 						} else {
3347 							UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3348 						}
3349 						break;
3350 					case ZEND_FETCH_CLASS_STATIC:
3351 					default:
3352 						UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3353 						break;
3354 				}
3355 			} else if (opline->op2_type == IS_CONST) {
3356 				zval *zv = CRT_CONSTANT(opline->op2);
3357 				if (Z_TYPE_P(zv) == IS_STRING) {
3358 					ce = zend_optimizer_get_class_entry(script, op_array, Z_STR_P(zv+1));
3359 					UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def);
3360 				} else {
3361 					UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3362 				}
3363 			} else {
3364 				COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->result_def);
3365 			}
3366 			break;
3367 		case ZEND_NEW:
3368 			tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT;
3369 			ce = zend_optimizer_get_class_entry_from_op1(script, op_array, opline);
3370 			if (ce) {
3371 				UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def);
3372 			} else if ((t1 & MAY_BE_CLASS) && ssa_op->op1_use >= 0 && ssa_var_info[ssa_op->op1_use].ce) {
3373 				UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_op->op1_use].ce, ssa_var_info[ssa_op->op1_use].is_instanceof, ssa_op->result_def);
3374 			} else {
3375 				UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3376 			}
3377 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3378 			break;
3379 		case ZEND_CLONE:
3380 			UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def);
3381 			COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
3382 			break;
3383 		case ZEND_INIT_ARRAY:
3384 		case ZEND_ADD_ARRAY_ELEMENT:
3385 			if (ssa_op->op1_def >= 0) {
3386 				if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
3387 					tmp = (MAY_BE_REF | t1) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3388 					if (t1 & MAY_BE_UNDEF) {
3389 						tmp |= MAY_BE_NULL;
3390 					}
3391 				} else if ((t1 & (MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN)) == MAY_BE_REF) {
3392 					tmp = (MAY_BE_REF | t1) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3393 					if (t1 & MAY_BE_UNDEF) {
3394 						tmp |= MAY_BE_NULL;
3395 					}
3396 				} else if (t1 & MAY_BE_REF) {
3397 					tmp = (MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | t1);
3398 				} else {
3399 					tmp = t1;
3400 					if (t1 & MAY_BE_RC1) {
3401 						tmp |= MAY_BE_RCN;
3402 					}
3403 				}
3404 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3405 			}
3406 			if (ssa_op->result_def >= 0) {
3407 				uint32_t arr_type;
3408 				if (opline->opcode == ZEND_INIT_ARRAY) {
3409 					arr_type = 0;
3410 				} else {
3411 					arr_type = RES_USE_INFO();
3412 				}
3413 				tmp = MAY_BE_RC1|MAY_BE_ARRAY|arr_type;
3414 				if (opline->opcode == ZEND_INIT_ARRAY && opline->op1_type == IS_UNUSED) {
3415 					tmp |= MAY_BE_ARRAY_EMPTY;
3416 				}
3417 				if (opline->op1_type != IS_UNUSED
3418 				 && (opline->op2_type == IS_UNUSED
3419 				  || (t2 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_STRING)))) {
3420 					tmp |= assign_dim_array_result_type(arr_type, t2, t1, opline->op2_type);
3421 					if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
3422 						tmp |= MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3423 					}
3424 				}
3425 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3426 			}
3427 			break;
3428 		case ZEND_ADD_ARRAY_UNPACK:
3429 			tmp = ssa_var_info[ssa_op->result_use].type;
3430 			ZEND_ASSERT(tmp & MAY_BE_ARRAY);
3431 			tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
3432 			if (t1 & MAY_BE_OBJECT) {
3433 				tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
3434 			}
3435 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3436 			break;
3437 		case ZEND_UNSET_CV:
3438 			tmp = MAY_BE_UNDEF;
3439 			if (!op_array->function_name) {
3440 				/* In global scope, we know nothing */
3441 				tmp |= MAY_BE_REF;
3442 			}
3443 			UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3444 			break;
3445 		case ZEND_UNSET_DIM:
3446 		case ZEND_UNSET_OBJ:
3447 			if (ssa_op->op1_def >= 0) {
3448 				UPDATE_SSA_TYPE(t1, ssa_op->op1_def);
3449 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3450 			}
3451 			break;
3452 		case ZEND_FE_RESET_R:
3453 		case ZEND_FE_RESET_RW:
3454 			if (ssa_op->op1_def >= 0) {
3455 				tmp = t1;
3456 				if (opline->opcode == ZEND_FE_RESET_RW) {
3457 					tmp |= MAY_BE_REF;
3458 				} else if (t1 & MAY_BE_RC1) {
3459 					tmp |= MAY_BE_RCN;
3460 				}
3461 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3462 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3463 			}
3464 			if (opline->opcode == ZEND_FE_RESET_RW) {
3465 //???
3466 				tmp = MAY_BE_REF | (t1 & (MAY_BE_ARRAY | MAY_BE_OBJECT));
3467 			} else {
3468 				tmp = MAY_BE_RC1 | MAY_BE_RCN | (t1 & (MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF));
3469 			}
3470 			/* The result is set to UNDEF for invalid foreach inputs. */
3471 			if ((t1 & (MAY_BE_ANY | MAY_BE_UNDEF)) & ~(MAY_BE_ARRAY | MAY_BE_OBJECT)) {
3472 				tmp |= MAY_BE_UNDEF;
3473 			}
3474 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3475 			COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
3476 			break;
3477 		case ZEND_FE_FETCH_R:
3478 		case ZEND_FE_FETCH_RW:
3479 			tmp = 0;
3480 			if (opline->op2_type == IS_CV) {
3481 				tmp = t2 & MAY_BE_REF;
3482 			}
3483 			if (t1 & MAY_BE_OBJECT) {
3484 				if (opline->opcode == ZEND_FE_FETCH_RW) {
3485 					tmp |= MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3486 				} else {
3487 					tmp |= MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3488 					if (opline->op2_type != IS_CV) {
3489 						tmp |= MAY_BE_REF;
3490 					}
3491 				}
3492 			}
3493 			if (t1 & MAY_BE_ARRAY) {
3494 				if (opline->opcode == ZEND_FE_FETCH_RW) {
3495 					tmp |= MAY_BE_REF | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3496 				} else {
3497 					tmp |= ((t1 & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
3498 					if (tmp & MAY_BE_ARRAY) {
3499 						tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3500 					}
3501 					if (t1 & MAY_BE_ARRAY_OF_REF) {
3502 						tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3503 						if (opline->op2_type != IS_CV) {
3504 							tmp |= MAY_BE_REF;
3505 						}
3506 					} else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
3507 						tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3508 					}
3509 				}
3510 			}
3511 			UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3512 			if (ssa_op->result_def >= 0) {
3513 				tmp = (ssa_op->result_use >= 0) ? RES_USE_INFO() : 0;
3514 				if (t1 & MAY_BE_OBJECT) {
3515 					tmp |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3516 				}
3517 				if (t1 & MAY_BE_ARRAY) {
3518 					if (t1 & MAY_BE_ARRAY_KEY_LONG) {
3519 						tmp |= MAY_BE_LONG;
3520 					}
3521 					if (t1 & MAY_BE_ARRAY_KEY_STRING) {
3522 						tmp |= MAY_BE_STRING | MAY_BE_RCN;
3523 					}
3524 				}
3525 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3526 			}
3527 			break;
3528 		case ZEND_FETCH_DIM_R:
3529 		case ZEND_FETCH_DIM_IS:
3530 		case ZEND_FETCH_DIM_RW:
3531 		case ZEND_FETCH_DIM_W:
3532 		case ZEND_FETCH_DIM_UNSET:
3533 		case ZEND_FETCH_DIM_FUNC_ARG:
3534 		case ZEND_FETCH_LIST_R:
3535 		case ZEND_FETCH_LIST_W:
3536 			if (ssa_op->op1_def >= 0) {
3537 				uint32_t key_type = 0;
3538 				tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN);
3539 				if (opline->opcode == ZEND_FETCH_DIM_W ||
3540 				    opline->opcode == ZEND_FETCH_DIM_RW ||
3541 				    opline->opcode == ZEND_FETCH_DIM_FUNC_ARG ||
3542 				    opline->opcode == ZEND_FETCH_LIST_W) {
3543 					if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3544 						if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) {
3545 							tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE);
3546 						}
3547 						tmp |= MAY_BE_ARRAY | MAY_BE_RC1;
3548 					}
3549 					if (t1 & (MAY_BE_STRING|MAY_BE_ARRAY)) {
3550 						tmp |= MAY_BE_RC1;
3551 						if (opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) {
3552 							tmp |= t1 & MAY_BE_RCN;
3553 						}
3554 					}
3555 					if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
3556 						tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
3557 					}
3558 					if (opline->op2_type == IS_UNUSED) {
3559 						if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3560 							key_type |= MAY_BE_ARRAY_PACKED;
3561 						}
3562 						if (t1 & MAY_BE_ARRAY) {
3563 							key_type |= MAY_BE_HASH_ONLY(t1) ?
3564 								MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3565 						}
3566 					} else {
3567 						if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
3568 							if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3569 								key_type |= MAY_BE_ARRAY_PACKED;
3570 							}
3571 							if (t1 & MAY_BE_ARRAY) {
3572 								key_type |= MAY_BE_HASH_ONLY(t1) ?
3573 									MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3574 						    }
3575 						}
3576 						if (t2 & MAY_BE_STRING) {
3577 							key_type |= MAY_BE_ARRAY_KEY_STRING;
3578 							if (opline->op2_type != IS_CONST) {
3579 								// FIXME: numeric string
3580 								if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3581 									key_type |= MAY_BE_ARRAY_PACKED;
3582 								}
3583 								if (t1 & MAY_BE_ARRAY) {
3584 									key_type |= MAY_BE_HASH_ONLY(t1) ?
3585 										MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3586 							    }
3587 							}
3588 						}
3589 						if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
3590 							key_type |= MAY_BE_ARRAY_KEY_STRING;
3591 						}
3592 					}
3593 				} else if (opline->opcode == ZEND_FETCH_DIM_UNSET) {
3594 					if (t1 & MAY_BE_ARRAY) {
3595 						tmp |= MAY_BE_RC1;
3596 					}
3597 					if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
3598 						tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
3599 					}
3600 				}
3601 				if ((key_type & (MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING))
3602 						&& (opline->opcode == ZEND_FETCH_DIM_RW
3603 						|| opline->opcode == ZEND_FETCH_DIM_W
3604 						|| opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
3605 						|| opline->opcode == ZEND_FETCH_LIST_W)) {
3606 					j = ssa_vars[ssa_op->result_def].use_chain;
3607 					if (j < 0) {
3608 						/* no uses */
3609 						tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_NULL;
3610 					}
3611 					while (j >= 0) {
3612 						uint8_t opcode;
3613 
3614 						if (!ssa_opcodes) {
3615 							if (j != (opline - op_array->opcodes) + 1) {
3616 								/* Use must be in next opline */
3617 								tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3618 								break;
3619 							}
3620 							opcode = op_array->opcodes[j].opcode;
3621 						} else {
3622 							if (ssa_opcodes[j] != opline + 1) {
3623 								/* Use must be in next opline */
3624 								tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3625 								break;
3626 							}
3627 							opcode = ssa_opcodes[j]->opcode;
3628 						}
3629 						switch (opcode) {
3630 							case ZEND_FETCH_DIM_W:
3631 							case ZEND_FETCH_DIM_RW:
3632 							case ZEND_FETCH_DIM_FUNC_ARG:
3633 							case ZEND_FETCH_LIST_W:
3634 							case ZEND_ASSIGN_DIM:
3635 							case ZEND_ASSIGN_DIM_OP:
3636 								tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_ARRAY;
3637 								break;
3638 							case ZEND_SEND_VAR_EX:
3639 							case ZEND_SEND_FUNC_ARG:
3640 							case ZEND_SEND_VAR_NO_REF:
3641 							case ZEND_SEND_VAR_NO_REF_EX:
3642 							case ZEND_SEND_REF:
3643 							case ZEND_ASSIGN_REF:
3644 							case ZEND_YIELD:
3645 							case ZEND_INIT_ARRAY:
3646 							case ZEND_ADD_ARRAY_ELEMENT:
3647 							case ZEND_RETURN_BY_REF:
3648 							case ZEND_VERIFY_RETURN_TYPE:
3649 							case ZEND_MAKE_REF:
3650 							case ZEND_FE_RESET_RW:
3651 								tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3652 								break;
3653 							case ZEND_PRE_INC:
3654 							case ZEND_PRE_DEC:
3655 							case ZEND_POST_INC:
3656 							case ZEND_POST_DEC:
3657 								if (tmp & MAY_BE_ARRAY_OF_LONG) {
3658 									/* may overflow */
3659 									tmp |= key_type | MAY_BE_ARRAY_OF_DOUBLE;
3660 								} else if (!(tmp & (MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_DOUBLE))) {
3661 									tmp |= key_type | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE;
3662 								}
3663 								break;
3664 							case ZEND_FETCH_OBJ_W:
3665 							case ZEND_FETCH_OBJ_RW:
3666 							case ZEND_FETCH_OBJ_FUNC_ARG:
3667 							case ZEND_ASSIGN_OBJ:
3668 							case ZEND_ASSIGN_OBJ_OP:
3669 							case ZEND_ASSIGN_OBJ_REF:
3670 							case ZEND_PRE_INC_OBJ:
3671 							case ZEND_PRE_DEC_OBJ:
3672 							case ZEND_POST_INC_OBJ:
3673 							case ZEND_POST_DEC_OBJ:
3674 								/* These will result in an error exception, unless the element
3675 								 * is already an object. */
3676 								break;
3677 							case ZEND_SEND_VAR:
3678 							case ZEND_FETCH_DIM_R:
3679 								/* This can occur if a DIM_FETCH_FUNC_ARG with UNUSED op2 is left
3680 								 * behind, because it can't be converted to DIM_FETCH_R. */
3681 								break;
3682 							case ZEND_FREE:
3683 								/* This may happen if the using opcode is DCEd.  */
3684 								break;
3685 							EMPTY_SWITCH_DEFAULT_CASE()
3686 						}
3687 						j = zend_ssa_next_use(ssa->ops, ssa_op->result_def, j);
3688 						if (j >= 0) {
3689 							tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3690 							break;
3691 						}
3692 					}
3693 					if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) {
3694 						tmp &= ~MAY_BE_ARRAY_EMPTY;
3695 					}
3696 				}
3697 				if (!(tmp & MAY_BE_ARRAY)
3698 				 || (tmp & MAY_BE_ARRAY_KEY_ANY)
3699 				 || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
3700 				 || opline->opcode == ZEND_FETCH_DIM_R
3701 				 || opline->opcode == ZEND_FETCH_DIM_IS
3702 				 || opline->opcode == ZEND_FETCH_DIM_UNSET
3703 				 || opline->opcode == ZEND_FETCH_LIST_R) {
3704 					UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3705 				} else {
3706 					/* invalid key type */
3707 					return SUCCESS;
3708 				}
3709 				COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3710 			}
3711 			/* FETCH_LIST on a string behaves like FETCH_R on null */
3712 			tmp = zend_array_element_type(
3713 				opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL),
3714 				opline->op1_type,
3715 				opline->opcode != ZEND_FETCH_DIM_R && opline->opcode != ZEND_FETCH_DIM_IS
3716 					&& opline->opcode != ZEND_FETCH_LIST_R,
3717 				opline->op2_type == IS_UNUSED);
3718 			if (opline->opcode == ZEND_FETCH_DIM_FUNC_ARG && (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE))) {
3719 				tmp |= MAY_BE_NULL;
3720 			}
3721 			if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) {
3722 				tmp |= MAY_BE_NULL;
3723 			}
3724 			if ((tmp & (MAY_BE_RC1|MAY_BE_RCN)) == MAY_BE_RCN && opline->result_type == IS_TMP_VAR) {
3725 				/* refcount may be indirectly decremented. Make an exception if the result is used in the next instruction */
3726 				if (!ssa_opcodes) {
3727 					if (ssa->vars[ssa_op->result_def].use_chain < 0
3728 					 || opline + 1 != op_array->opcodes + ssa->vars[ssa_op->result_def].use_chain) {
3729 						tmp |= MAY_BE_RC1;
3730 				    }
3731 				} else {
3732 					if (ssa->vars[ssa_op->result_def].use_chain < 0
3733 					 || opline + 1 != ssa_opcodes[ssa->vars[ssa_op->result_def].use_chain]) {
3734 						tmp |= MAY_BE_RC1;
3735 				    }
3736 				}
3737 			}
3738 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3739 			break;
3740 		case ZEND_FETCH_THIS:
3741 			if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
3742 				UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_op->result_def);
3743 			}
3744 			UPDATE_SSA_TYPE(MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def);
3745 			break;
3746 		case ZEND_FETCH_OBJ_R:
3747 		case ZEND_FETCH_OBJ_IS:
3748 		case ZEND_FETCH_OBJ_RW:
3749 		case ZEND_FETCH_OBJ_W:
3750 		case ZEND_FETCH_OBJ_UNSET:
3751 		case ZEND_FETCH_OBJ_FUNC_ARG:
3752 			if (ssa_op->result_def >= 0) {
3753 				uint32_t tmp = 0;
3754 				ce = NULL;
3755 				if (opline->op1_type != IS_UNUSED
3756 						&& (t1 & (MAY_BE_ANY | MAY_BE_UNDEF) & ~MAY_BE_OBJECT)) {
3757 					tmp |= MAY_BE_NULL;
3758 				}
3759 				if (opline->op1_type == IS_UNUSED || (t1 & MAY_BE_OBJECT)) {
3760 					const zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
3761 					tmp |= zend_fetch_prop_type(script, prop_info, &ce);
3762 					if (opline->opcode != ZEND_FETCH_OBJ_R && opline->opcode != ZEND_FETCH_OBJ_IS) {
3763 						tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
3764 						if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) {
3765 							tmp |= MAY_BE_UNDEF;
3766 						}
3767 						ce = NULL;
3768 					} else if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || !(t1 & MAY_BE_RC1)) {
3769 						const zend_class_entry *ce = NULL;
3770 
3771 						if (opline->op1_type == IS_UNUSED) {
3772 							ce = op_array->scope;
3773 						} else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) {
3774 							ce = ssa->var_info[ssa_op->op1_use].ce;
3775 						}
3776 						/* Unset properties will resort back to __get/__set */
3777 						if (ce
3778 						 && !ce->create_object
3779 						 && ce->default_object_handlers->read_property == zend_std_read_property
3780 						 && !ce->__get
3781 						 && !result_may_be_separated(ssa, ssa_op)) {
3782 							tmp &= ~MAY_BE_RC1;
3783 						}
3784 						if (opline->opcode == ZEND_FETCH_OBJ_IS) {
3785 							/* IS check may return null for uninitialized typed property. */
3786 							tmp |= MAY_BE_NULL;
3787 						}
3788 					}
3789 				}
3790 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3791 				if (ce) {
3792 					UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3793 				}
3794 			}
3795 			break;
3796 		case ZEND_FETCH_STATIC_PROP_R:
3797 		case ZEND_FETCH_STATIC_PROP_IS:
3798 		case ZEND_FETCH_STATIC_PROP_RW:
3799 		case ZEND_FETCH_STATIC_PROP_W:
3800 		case ZEND_FETCH_STATIC_PROP_UNSET:
3801 		case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
3802 			tmp = zend_fetch_prop_type(script,
3803 				zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
3804 			if (opline->opcode != ZEND_FETCH_STATIC_PROP_R
3805 					&& opline->opcode != ZEND_FETCH_STATIC_PROP_IS) {
3806 				tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
3807 				if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) {
3808 					tmp |= MAY_BE_UNDEF;
3809 				}
3810 				ce = NULL;
3811 			} else {
3812 				if (!result_may_be_separated(ssa, ssa_op)) {
3813 					tmp &= ~MAY_BE_RC1;
3814 				}
3815 				if (opline->opcode == ZEND_FETCH_STATIC_PROP_IS) {
3816 					tmp |= MAY_BE_UNDEF;
3817 				}
3818 			}
3819 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3820 			if (ce) {
3821 				UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3822 			}
3823 			break;
3824 		case ZEND_DO_FCALL:
3825 		case ZEND_DO_ICALL:
3826 		case ZEND_DO_UCALL:
3827 		case ZEND_DO_FCALL_BY_NAME:
3828 			if (ssa_op->result_def >= 0) {
3829 				zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
3830 				zend_call_info *call_info;
3831 
3832 				if (!func_info || !func_info->call_map) {
3833 					goto unknown_opcode;
3834 				}
3835 				call_info = func_info->call_map[opline - op_array->opcodes];
3836 				if (!call_info) {
3837 					goto unknown_opcode;
3838 				}
3839 
3840 				zend_class_entry *ce;
3841 				bool ce_is_instanceof;
3842 				tmp = zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof);
3843 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3844 				if (ce) {
3845 					UPDATE_SSA_OBJ_TYPE(ce, ce_is_instanceof, ssa_op->result_def);
3846 				}
3847 			}
3848 			break;
3849 		case ZEND_CALLABLE_CONVERT:
3850 			UPDATE_SSA_TYPE(MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN, ssa_op->result_def);
3851 			UPDATE_SSA_OBJ_TYPE(zend_ce_closure, /* is_instanceof */ false, ssa_op->result_def);
3852 			break;
3853 		case ZEND_FETCH_CONSTANT:
3854 		case ZEND_FETCH_CLASS_CONSTANT:
3855 			UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY, ssa_op->result_def);
3856 			break;
3857 		case ZEND_STRLEN:
3858 		case ZEND_COUNT:
3859 		case ZEND_FUNC_NUM_ARGS:
3860 			UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def);
3861 			break;
3862 		case ZEND_FUNC_GET_ARGS:
3863 			UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ARRAY|MAY_BE_ARRAY_EMPTY|MAY_BE_ARRAY_PACKED|MAY_BE_ARRAY_OF_ANY, ssa_op->result_def);
3864 			break;
3865 		case ZEND_GET_CLASS:
3866 		case ZEND_GET_CALLED_CLASS:
3867 			UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RCN, ssa_op->result_def);
3868 			break;
3869 		case ZEND_GET_TYPE:
3870 			UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_op->result_def);
3871 			break;
3872 		case ZEND_TYPE_CHECK: {
3873 			uint32_t expected_type_mask = opline->extended_value;
3874 			if (t1 & MAY_BE_UNDEF) {
3875 				t1 |= MAY_BE_NULL;
3876 			}
3877 			tmp = 0;
3878 			if (t1 & expected_type_mask) {
3879 				tmp |= MAY_BE_TRUE;
3880 				if ((t1 & expected_type_mask) & MAY_BE_RESOURCE) {
3881 					tmp |= MAY_BE_FALSE;
3882 				}
3883 			}
3884 			if (t1 & (MAY_BE_ANY - expected_type_mask)) {
3885 				tmp |= MAY_BE_FALSE;
3886 			}
3887 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3888 			break;
3889 		}
3890 		case ZEND_DEFINED:
3891 			UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_op->result_def);
3892 			break;
3893 		case ZEND_VERIFY_RETURN_TYPE:
3894 			if (t1 & MAY_BE_REF) {
3895 				tmp = t1;
3896 				ce = NULL;
3897 			} else {
3898 				zend_arg_info *ret_info = op_array->arg_info - 1;
3899 				tmp = zend_fetch_arg_info_type(script, ret_info, &ce);
3900 				tmp |= (t1 & MAY_BE_INDIRECT);
3901 
3902 				// TODO: We could model more precisely how illegal types are converted.
3903 				uint32_t extra_types = t1 & ~tmp;
3904 				if (!extra_types) {
3905 					tmp &= t1;
3906 				}
3907 			}
3908 			if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
3909 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3910 				if (ce) {
3911 					UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->op1_def);
3912 				} else {
3913 					UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->op1_def);
3914 				}
3915 			} else {
3916 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3917 				if (ce) {
3918 					UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3919 				} else {
3920 					UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3921 				}
3922 			}
3923 			break;
3924 		case ZEND_MAKE_REF:
3925 			tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3926 			UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3927 			if (ssa_op->op1_def >= 0) {
3928 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3929 			}
3930 			break;
3931 		case ZEND_CATCH:
3932 			/* Forbidden opcodes */
3933 			ZEND_UNREACHABLE();
3934 			break;
3935 		default:
3936 unknown_opcode:
3937 			if (ssa_op->op1_def >= 0) {
3938 				tmp = MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3939 				UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3940 			}
3941 			if (ssa_op->result_def >= 0) {
3942 				tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3943 				if (opline->result_type == IS_TMP_VAR) {
3944 					if (opline->opcode == ZEND_FETCH_R || opline->opcode == ZEND_FETCH_IS) {
3945 						/* Variable reference counter may be decremented before use */
3946 						/* See: ext/opcache/tests/jit/fetch_r_001.phpt */
3947 						tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3948 					} else {
3949 						tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3950 					}
3951 				} else if (opline->result_type == IS_CV) {
3952 					tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3953 				} else {
3954 					tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
3955 					switch (opline->opcode) {
3956 						case ZEND_FETCH_W:
3957 						case ZEND_FETCH_RW:
3958 						case ZEND_FETCH_FUNC_ARG:
3959 						case ZEND_FETCH_UNSET:
3960 						case ZEND_FETCH_DIM_W:
3961 						case ZEND_FETCH_DIM_RW:
3962 						case ZEND_FETCH_DIM_FUNC_ARG:
3963 						case ZEND_FETCH_DIM_UNSET:
3964 						case ZEND_FETCH_OBJ_W:
3965 						case ZEND_FETCH_OBJ_RW:
3966 						case ZEND_FETCH_OBJ_FUNC_ARG:
3967 						case ZEND_FETCH_OBJ_UNSET:
3968 						case ZEND_FETCH_STATIC_PROP_W:
3969 						case ZEND_FETCH_STATIC_PROP_RW:
3970 						case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
3971 						case ZEND_FETCH_STATIC_PROP_UNSET:
3972 							tmp |= MAY_BE_INDIRECT;
3973 							break;
3974 					}
3975 				}
3976 				UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3977 			}
3978 			break;
3979 	}
3980 
3981 	return SUCCESS;
3982 }
3983 
zend_update_type_info(const zend_op_array * op_array,zend_ssa * ssa,const zend_script * script,zend_op * opline,zend_ssa_op * ssa_op,const zend_op ** ssa_opcodes,zend_long optimization_level)3984 ZEND_API zend_result zend_update_type_info(
3985 			const zend_op_array *op_array,
3986 			zend_ssa            *ssa,
3987 			const zend_script   *script,
3988 			zend_op             *opline,
3989 			zend_ssa_op         *ssa_op,
3990 			const zend_op      **ssa_opcodes,
3991 			zend_long            optimization_level)
3992 {
3993 	return _zend_update_type_info(op_array, ssa, script, NULL, opline, ssa_op, ssa_opcodes, optimization_level, 0);
3994 }
3995 
get_class_entry_rank(zend_class_entry * ce)3996 static uint32_t get_class_entry_rank(zend_class_entry *ce) {
3997 	uint32_t rank = 0;
3998 	if (ce->ce_flags & ZEND_ACC_LINKED) {
3999 		while (ce->parent) {
4000 			rank++;
4001 			ce = ce->parent;
4002 		}
4003 	}
4004 	return rank;
4005 }
4006 
4007 /* Compute least common ancestor on class inheritance tree only */
join_class_entries(zend_class_entry * ce1,zend_class_entry * ce2,int * is_instanceof)4008 static zend_class_entry *join_class_entries(
4009 		zend_class_entry *ce1, zend_class_entry *ce2, int *is_instanceof) {
4010 	uint32_t rank1, rank2;
4011 	if (ce1 == ce2) {
4012 		return ce1;
4013 	}
4014 	if (!ce1 || !ce2) {
4015 		return NULL;
4016 	}
4017 
4018 	rank1 = get_class_entry_rank(ce1);
4019 	rank2 = get_class_entry_rank(ce2);
4020 
4021 	while (rank1 != rank2) {
4022 		if (rank1 > rank2) {
4023 			ce1 = !(ce1->ce_flags & ZEND_ACC_LINKED) ? NULL : ce1->parent;
4024 			rank1--;
4025 		} else {
4026 			ce2 = !(ce2->ce_flags & ZEND_ACC_LINKED) ? NULL : ce2->parent;
4027 			rank2--;
4028 		}
4029 	}
4030 
4031 	while (ce1 != ce2) {
4032 		ce1 = !(ce1->ce_flags & ZEND_ACC_LINKED) ? NULL : ce1->parent;
4033 		ce2 = !(ce2->ce_flags & ZEND_ACC_LINKED) ? NULL : ce2->parent;
4034 	}
4035 
4036 	if (ce1) {
4037 		*is_instanceof = 1;
4038 	}
4039 	return ce1;
4040 }
4041 
safe_instanceof(zend_class_entry * ce1,zend_class_entry * ce2)4042 static bool safe_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) {
4043 	if (ce1 == ce2) {
4044 		return 1;
4045 	}
4046 	if (!(ce1->ce_flags & ZEND_ACC_LINKED)) {
4047 		/* This case could be generalized, similarly to unlinked_instanceof */
4048 		return 0;
4049 	}
4050 	return instanceof_function(ce1, ce2);
4051 }
4052 
zend_infer_types_ex(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_bitset worklist,zend_long optimization_level)4053 static zend_result zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level)
4054 {
4055 	zend_basic_block *blocks = ssa->cfg.blocks;
4056 	zend_ssa_var *ssa_vars = ssa->vars;
4057 	zend_ssa_var_info *ssa_var_info = ssa->var_info;
4058 	int ssa_vars_count = ssa->vars_count;
4059 	int i, j;
4060 	uint32_t tmp, worklist_len = zend_bitset_len(ssa_vars_count);
4061 	bool update_worklist = 1;
4062 	const zend_op **ssa_opcodes = NULL;
4063 
4064 	while (!zend_bitset_empty(worklist, worklist_len)) {
4065 		j = zend_bitset_first(worklist, worklist_len);
4066 		zend_bitset_excl(worklist, j);
4067 		if (ssa_vars[j].definition_phi) {
4068 			zend_ssa_phi *p = ssa_vars[j].definition_phi;
4069 			if (p->pi >= 0) {
4070 				zend_class_entry *ce = ssa_var_info[p->sources[0]].ce;
4071 				int is_instanceof = ssa_var_info[p->sources[0]].is_instanceof;
4072 				tmp = get_ssa_var_info(ssa, p->sources[0]);
4073 
4074 				if (!p->has_range_constraint) {
4075 					zend_ssa_type_constraint *constraint = &p->constraint.type;
4076 					tmp &= constraint->type_mask;
4077 					if (!(tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
4078 						tmp &= ~(MAY_BE_RC1|MAY_BE_RCN);
4079 					}
4080 					if ((tmp & MAY_BE_OBJECT) && constraint->ce && ce != constraint->ce) {
4081 						if (!ce) {
4082 							ce = constraint->ce;
4083 							is_instanceof = 1;
4084 						} else if (is_instanceof && safe_instanceof(constraint->ce, ce)) {
4085 							ce = constraint->ce;
4086 						} else {
4087 							/* Ignore the constraint (either ce instanceof constraint->ce or
4088 							 * they are unrelated, as far as we can statically determine) */
4089 						}
4090 					}
4091 				}
4092 
4093 				UPDATE_SSA_TYPE(tmp, j);
4094 				if (tmp & MAY_BE_REF) {
4095 					UPDATE_SSA_OBJ_TYPE(NULL, 0, j);
4096 				} else {
4097 					UPDATE_SSA_OBJ_TYPE(ce, is_instanceof, j);
4098 				}
4099 			} else {
4100 				int first = 1;
4101 				int is_instanceof = 0;
4102 				zend_class_entry *ce = NULL;
4103 
4104 				tmp = 0;
4105 				for (i = 0; i < blocks[p->block].predecessors_count; i++) {
4106 					tmp |= get_ssa_var_info(ssa, p->sources[i]);
4107 				}
4108 				UPDATE_SSA_TYPE(tmp, j);
4109 				for (i = 0; i < blocks[p->block].predecessors_count; i++) {
4110 					zend_ssa_var_info *info;
4111 
4112 					ZEND_ASSERT(p->sources[i] >= 0);
4113 					info = &ssa_var_info[p->sources[i]];
4114 					if (info->type & MAY_BE_OBJECT) {
4115 						if (first) {
4116 							ce = info->ce;
4117 							is_instanceof = info->is_instanceof;
4118 							first = 0;
4119 						} else {
4120 							is_instanceof |= info->is_instanceof;
4121 							ce = join_class_entries(ce, info->ce, &is_instanceof);
4122 						}
4123 					}
4124 				}
4125 				UPDATE_SSA_OBJ_TYPE(ce, ce ? is_instanceof : 0, j);
4126 			}
4127 		} else if (ssa_vars[j].definition >= 0) {
4128 			i = ssa_vars[j].definition;
4129 			if (_zend_update_type_info(op_array, ssa, script, worklist, op_array->opcodes + i, ssa->ops + i, NULL, optimization_level, 1) == FAILURE) {
4130 				return FAILURE;
4131 			}
4132 		}
4133 	}
4134 	return SUCCESS;
4135 }
4136 
is_narrowable_instr(zend_op * opline)4137 static bool is_narrowable_instr(zend_op *opline)  {
4138 	return opline->opcode == ZEND_ADD || opline->opcode == ZEND_SUB
4139 		|| opline->opcode == ZEND_MUL || opline->opcode == ZEND_DIV;
4140 }
4141 
is_effective_op1_double_cast(zend_op * opline,zval * op2)4142 static bool is_effective_op1_double_cast(zend_op *opline, zval *op2) {
4143 	return (opline->opcode == ZEND_ADD && Z_LVAL_P(op2) == 0)
4144 		|| (opline->opcode == ZEND_SUB && Z_LVAL_P(op2) == 0)
4145 		|| (opline->opcode == ZEND_MUL && Z_LVAL_P(op2) == 1)
4146 		|| (opline->opcode == ZEND_DIV && Z_LVAL_P(op2) == 1);
4147 }
is_effective_op2_double_cast(zend_op * opline,zval * op1)4148 static bool is_effective_op2_double_cast(zend_op *opline, zval *op1) {
4149 	/* In PHP it holds that (double)(0-$int) is bitwise identical to 0.0-(double)$int,
4150 	 * so allowing SUB here is fine. */
4151 	return (opline->opcode == ZEND_ADD && Z_LVAL_P(op1) == 0)
4152 		|| (opline->opcode == ZEND_SUB && Z_LVAL_P(op1) == 0)
4153 		|| (opline->opcode == ZEND_MUL && Z_LVAL_P(op1) == 1);
4154 }
4155 
4156 /* This function recursively checks whether it's possible to convert an integer variable
4157  * initialization to a double initialization. The basic idea is that if the value is used
4158  * only in add/sub/mul/div ("narrowable" instructions) with a double result value, then it
4159  * will be cast to double at that point anyway, so we may as well do it earlier already.
4160  *
4161  * The tricky case are chains of operations, where it's not necessarily a given that converting
4162  * an integer to double before the chain of operations is the same as converting it after the
4163  * chain. What this function does is detect two cases where it is safe:
4164  *  * If the operations only involve constants, then we can simply verify that performing the
4165  *    calculation on integers and doubles yields the same value.
4166  *  * Even if one operand is not known, we may be able to determine that the operations with the
4167  *    integer replaced by a double only acts as an effective double cast on the unknown operand.
4168  *    E.g. 0+$i and 0.0+$i only differ by that cast. If then the consuming instruction of this
4169  *    result will perform a double cast anyway, the conversion is safe.
4170  *
4171  * The checks happens recursively, while keeping track of which variables are already visited to
4172  * avoid infinite loops. An iterative, worklist driven approach would be possible, but the state
4173  * management more cumbersome to implement, so we don't bother for now.
4174  */
can_convert_to_double(const zend_op_array * op_array,zend_ssa * ssa,int var_num,zval * value,zend_bitset visited)4175 static bool can_convert_to_double(
4176 		const zend_op_array *op_array, zend_ssa *ssa, int var_num,
4177 		zval *value, zend_bitset visited) {
4178 	zend_ssa_var *var = &ssa->vars[var_num];
4179 	zend_ssa_phi *phi;
4180 	int use;
4181 	uint32_t type;
4182 
4183 	if (zend_bitset_in(visited, var_num)) {
4184 		return 1;
4185 	}
4186 	zend_bitset_incl(visited, var_num);
4187 
4188 	for (use = var->use_chain; use >= 0; use = zend_ssa_next_use(ssa->ops, var_num, use)) {
4189 		zend_op *opline = &op_array->opcodes[use];
4190 		zend_ssa_op *ssa_op = &ssa->ops[use];
4191 
4192 		if (zend_ssa_is_no_val_use(opline, ssa_op, var_num)) {
4193 			continue;
4194 		}
4195 
4196 		if (!is_narrowable_instr(opline)) {
4197 			return 0;
4198 		}
4199 
4200 		/* Instruction always returns double, the conversion is certainly fine */
4201 		type = ssa->var_info[ssa_op->result_def].type;
4202 		if ((type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4203 			continue;
4204 		}
4205 
4206 		/* UNDEF signals that the previous result is an effective double cast, this is only allowed
4207 		 * if this instruction would have done the cast anyway (previous check). */
4208 		if (Z_ISUNDEF_P(value)) {
4209 			return 0;
4210 		}
4211 
4212 		/* Check that narrowing can actually be useful */
4213 		if ((type & MAY_BE_ANY) & ~(MAY_BE_LONG|MAY_BE_DOUBLE)) {
4214 			return 0;
4215 		}
4216 
4217 		{
4218 			/* For calculation on original values */
4219 			zval orig_op1, orig_op2, orig_result;
4220 			/* For calculation with var_num cast to double */
4221 			zval dval_op1, dval_op2, dval_result;
4222 
4223 			ZVAL_UNDEF(&orig_op1);
4224 			ZVAL_UNDEF(&dval_op1);
4225 			if (ssa_op->op1_use == var_num) {
4226 				ZVAL_COPY_VALUE(&orig_op1, value);
4227 				ZVAL_DOUBLE(&dval_op1, (double) Z_LVAL_P(value));
4228 			} else if (opline->op1_type == IS_CONST) {
4229 				zval *zv = CRT_CONSTANT(opline->op1);
4230 				if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
4231 					ZVAL_COPY_VALUE(&orig_op1, zv);
4232 					ZVAL_COPY_VALUE(&dval_op1, zv);
4233 				}
4234 			}
4235 
4236 			ZVAL_UNDEF(&orig_op2);
4237 			ZVAL_UNDEF(&dval_op2);
4238 			if (ssa_op->op2_use == var_num) {
4239 				ZVAL_COPY_VALUE(&orig_op2, value);
4240 				ZVAL_DOUBLE(&dval_op2, (double) Z_LVAL_P(value));
4241 			} else if (opline->op2_type == IS_CONST) {
4242 				zval *zv = CRT_CONSTANT(opline->op2);
4243 				if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
4244 					ZVAL_COPY_VALUE(&orig_op2, zv);
4245 					ZVAL_COPY_VALUE(&dval_op2, zv);
4246 				}
4247 			}
4248 
4249 			ZEND_ASSERT(!Z_ISUNDEF(orig_op1) || !Z_ISUNDEF(orig_op2));
4250 			if (Z_ISUNDEF(orig_op1)) {
4251 				if (opline->opcode == ZEND_MUL && Z_LVAL(orig_op2) == 0) {
4252 					ZVAL_LONG(&orig_result, 0);
4253 				} else if (is_effective_op1_double_cast(opline, &orig_op2)) {
4254 					ZVAL_UNDEF(&orig_result);
4255 				} else {
4256 					return 0;
4257 				}
4258 			} else if (Z_ISUNDEF(orig_op2)) {
4259 				if (opline->opcode == ZEND_MUL && Z_LVAL(orig_op1) == 0) {
4260 					ZVAL_LONG(&orig_result, 0);
4261 				} else if (is_effective_op2_double_cast(opline, &orig_op1)) {
4262 					ZVAL_UNDEF(&orig_result);
4263 				} else {
4264 					return 0;
4265 				}
4266 			} else {
4267 				uint8_t opcode = opline->opcode;
4268 
4269 				if (opcode == ZEND_ASSIGN_OP) {
4270 					opcode = opline->extended_value;
4271 				}
4272 
4273 				/* Avoid division by zero */
4274 				if (opcode == ZEND_DIV && zval_get_double(&orig_op2) == 0.0) {
4275 					return 0;
4276 				}
4277 
4278 				get_binary_op(opcode)(&orig_result, &orig_op1, &orig_op2);
4279 				get_binary_op(opcode)(&dval_result, &dval_op1, &dval_op2);
4280 				ZEND_ASSERT(Z_TYPE(dval_result) == IS_DOUBLE);
4281 				if (zval_get_double(&orig_result) != Z_DVAL(dval_result)) {
4282 					return 0;
4283 				}
4284 			}
4285 
4286 			if (!can_convert_to_double(op_array, ssa, ssa_op->result_def, &orig_result, visited)) {
4287 				return 0;
4288 			}
4289 		}
4290 	}
4291 
4292 	for (phi = var->phi_use_chain; phi; phi = zend_ssa_next_use_phi(ssa, var_num, phi)) {
4293 		/* Check that narrowing can actually be useful */
4294 		type = ssa->var_info[phi->ssa_var].type;
4295 		if ((type & MAY_BE_ANY) & ~(MAY_BE_LONG|MAY_BE_DOUBLE)) {
4296 			return 0;
4297 		}
4298 
4299 		if (!can_convert_to_double(op_array, ssa, phi->ssa_var, value, visited)) {
4300 			return 0;
4301 		}
4302 	}
4303 
4304 	return 1;
4305 }
4306 
zend_type_narrowing(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_long optimization_level)4307 static zend_result zend_type_narrowing(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
4308 {
4309 	uint32_t bitset_len = zend_bitset_len(ssa->vars_count);
4310 	zend_bitset visited, worklist;
4311 	int i, v;
4312 	zend_op *opline;
4313 	bool narrowed = 0;
4314 	ALLOCA_FLAG(use_heap)
4315 
4316 	visited = ZEND_BITSET_ALLOCA(2 * bitset_len, use_heap);
4317 	worklist = visited + bitset_len;
4318 
4319 	zend_bitset_clear(worklist, bitset_len);
4320 
4321 	for (v = op_array->last_var; v < ssa->vars_count; v++) {
4322 		if ((ssa->var_info[v].type & (MAY_BE_REF | MAY_BE_ANY | MAY_BE_UNDEF)) != MAY_BE_LONG) continue;
4323 		if (ssa->vars[v].definition < 0) continue;
4324 		if (ssa->vars[v].no_val) continue;
4325 		opline = op_array->opcodes + ssa->vars[v].definition;
4326 		/* Go through assignments of literal integers and check if they can be converted to
4327 		 * doubles instead, in the hope that we'll narrow long|double to double. */
4328 		if (opline->opcode == ZEND_ASSIGN && opline->result_type == IS_UNUSED &&
4329 				opline->op1_type == IS_CV && opline->op2_type == IS_CONST) {
4330 			zval *value = CRT_CONSTANT(opline->op2);
4331 
4332 			zend_bitset_clear(visited, bitset_len);
4333 			if (can_convert_to_double(op_array, ssa, v, value, visited)) {
4334 				narrowed = 1;
4335 				ssa->var_info[v].use_as_double = 1;
4336 				/* The "visited" vars are exactly those which may change their type due to
4337 				 * narrowing. Reset their types and add them to the type inference worklist */
4338 				ZEND_BITSET_FOREACH(visited, bitset_len, i) {
4339 					ssa->var_info[i].type &= ~MAY_BE_ANY;
4340 				} ZEND_BITSET_FOREACH_END();
4341 				zend_bitset_union(worklist, visited, bitset_len);
4342 			}
4343 		}
4344 	}
4345 
4346 	if (!narrowed) {
4347 		free_alloca(visited, use_heap);
4348 		return SUCCESS;
4349 	}
4350 
4351 	if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) == FAILURE) {
4352 		free_alloca(visited, use_heap);
4353 		return FAILURE;
4354 	}
4355 
4356 	free_alloca(visited, use_heap);
4357 	return SUCCESS;
4358 }
4359 
is_recursive_tail_call(const zend_op_array * op_array,zend_op * opline)4360 static bool is_recursive_tail_call(const zend_op_array *op_array,
4361                                   zend_op             *opline)
4362 {
4363 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
4364 
4365 	if (info->ssa.ops && info->ssa.vars && info->call_map &&
4366 	    info->ssa.ops[opline - op_array->opcodes].op1_use >= 0 &&
4367 	    info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition >= 0) {
4368 
4369 		zend_op *op = op_array->opcodes + info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition;
4370 
4371 		if (op->opcode == ZEND_DO_UCALL) {
4372 			zend_call_info *call_info = info->call_map[op - op_array->opcodes];
4373 			if (call_info && op_array == &call_info->callee_func->op_array) {
4374 				return 1;
4375 			}
4376 		}
4377 	}
4378 	return 0;
4379 }
4380 
zend_get_return_info_from_signature_only(const zend_function * func,const zend_script * script,zend_class_entry ** ce,bool * ce_is_instanceof,bool use_tentative_return_info)4381 uint32_t zend_get_return_info_from_signature_only(
4382 		const zend_function *func, const zend_script *script,
4383 		zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info) {
4384 	uint32_t type;
4385 	if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE &&
4386 		(use_tentative_return_info || !ZEND_ARG_TYPE_IS_TENTATIVE(func->common.arg_info - 1))
4387 	) {
4388 		zend_arg_info *ret_info = func->common.arg_info - 1;
4389 		type = zend_fetch_arg_info_type(script, ret_info, ce);
4390 		*ce_is_instanceof = ce != NULL;
4391 	} else {
4392 		type = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
4393 			| MAY_BE_RC1 | MAY_BE_RCN;
4394 		*ce = NULL;
4395 		*ce_is_instanceof = false;
4396 	}
4397 
4398 	/* For generators RETURN_REFERENCE refers to the yielded values. */
4399 	if ((func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
4400 			&& !(func->common.fn_flags & ZEND_ACC_GENERATOR)) {
4401 		type |= MAY_BE_REF;
4402 		*ce = NULL;
4403 		*ce_is_instanceof = 0;
4404 	}
4405 	return type;
4406 }
4407 
zend_init_func_return_info(const zend_op_array * op_array,const zend_script * script,zend_ssa_var_info * ret)4408 ZEND_API void zend_init_func_return_info(
4409 	const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
4410 {
4411 	ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE));
4412 
4413 	zend_ssa_range tmp_range = {0, 0, 0, 0};
4414 	bool is_instanceof = false;
4415 	ret->type = zend_get_return_info_from_signature_only(
4416 		(zend_function *) op_array, script, &ret->ce, &is_instanceof, /* use_tentative_return_info */ 1);
4417 	ret->is_instanceof = is_instanceof;
4418 	ret->range = tmp_range;
4419 	ret->has_range = 0;
4420 }
4421 
zend_func_return_info(const zend_op_array * op_array,const zend_script * script,int recursive,int widening,zend_ssa_var_info * ret)4422 static void zend_func_return_info(const zend_op_array   *op_array,
4423                                   const zend_script     *script,
4424                                   int                    recursive,
4425                                   int                    widening,
4426                                   zend_ssa_var_info     *ret)
4427 {
4428 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
4429 	zend_ssa *ssa = &info->ssa;
4430 	int blocks_count = info->ssa.cfg.blocks_count;
4431 	zend_basic_block *blocks = info->ssa.cfg.blocks;
4432 	int j;
4433 	uint32_t t1;
4434 	uint32_t tmp = 0;
4435 	zend_class_entry *tmp_ce = NULL;
4436 	int tmp_is_instanceof = -1;
4437 	zend_class_entry *arg_ce;
4438 	int arg_is_instanceof;
4439 	zend_ssa_range tmp_range = {0, 0, 0, 0};
4440 	int tmp_has_range = -1;
4441 
4442 	if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
4443 		ret->type = MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN;
4444 		ret->ce = zend_ce_generator;
4445 		ret->is_instanceof = 0;
4446 		ret->range = tmp_range;
4447 		ret->has_range = 0;
4448 		return;
4449 	}
4450 
4451 	if (!ret->type) {
4452 		/* We will intersect the type later. */
4453 		ret->type = MAY_BE_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY
4454 			| MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF;
4455 	}
4456 
4457 	for (j = 0; j < blocks_count; j++) {
4458 		if ((blocks[j].flags & ZEND_BB_REACHABLE) && blocks[j].len != 0) {
4459 			zend_op *opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1;
4460 
4461 			if (opline->opcode == ZEND_RETURN || opline->opcode == ZEND_RETURN_BY_REF) {
4462 				zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
4463 				if (!recursive && ssa_op && info->ssa.var_info &&
4464 				    ssa_op->op1_use >= 0 &&
4465 				    info->ssa.var_info[ssa_op->op1_use].recursive) {
4466 					continue;
4467 				}
4468 				if (is_recursive_tail_call(op_array, opline)) {
4469 					continue;
4470 				}
4471 				t1 = OP1_INFO();
4472 				if (t1 & MAY_BE_UNDEF) {
4473 					t1 |= MAY_BE_NULL;
4474 				}
4475 				if (opline->opcode == ZEND_RETURN) {
4476 					if (t1 & MAY_BE_RC1) {
4477 						t1 |= MAY_BE_RCN;
4478 					}
4479 					t1 &= ~(MAY_BE_UNDEF | MAY_BE_REF);
4480 				} else {
4481 					t1 |= MAY_BE_REF;
4482 					t1 &= ~(MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN);
4483 				}
4484 				tmp |= t1;
4485 
4486 				if (ssa_op && info->ssa.var_info &&
4487 				    ssa_op->op1_use >= 0 && !(t1 & MAY_BE_REF) &&
4488 				    info->ssa.var_info[ssa_op->op1_use].ce) {
4489 					arg_ce = info->ssa.var_info[ssa_op->op1_use].ce;
4490 					arg_is_instanceof = info->ssa.var_info[ssa_op->op1_use].is_instanceof;
4491 				} else {
4492 					arg_ce = NULL;
4493 					arg_is_instanceof = 0;
4494 				}
4495 
4496 				if (tmp_is_instanceof < 0) {
4497 					tmp_ce = arg_ce;
4498 					tmp_is_instanceof = arg_is_instanceof;
4499 				} else if (arg_ce && arg_ce == tmp_ce) {
4500 					if (tmp_is_instanceof != arg_is_instanceof) {
4501 						tmp_is_instanceof = 1;
4502 					}
4503 				} else {
4504 					tmp_ce = NULL;
4505 					tmp_is_instanceof = 0;
4506 				}
4507 
4508 				if (opline->op1_type == IS_CONST) {
4509 					zval *zv = CRT_CONSTANT(opline->op1);
4510 
4511 					if (Z_TYPE_P(zv) == IS_LONG) {
4512 						if (tmp_has_range < 0) {
4513 							tmp_has_range = 1;
4514 							tmp_range.underflow = 0;
4515 							tmp_range.min = Z_LVAL_P(zv);
4516 							tmp_range.max = Z_LVAL_P(zv);
4517 							tmp_range.overflow = 0;
4518 						} else if (tmp_has_range) {
4519 							if (!tmp_range.underflow) {
4520 								tmp_range.min = MIN(tmp_range.min, Z_LVAL_P(zv));
4521 							}
4522 							if (!tmp_range.overflow) {
4523 								tmp_range.max = MAX(tmp_range.max, Z_LVAL_P(zv));
4524 							}
4525 						}
4526 					} else {
4527 						tmp_has_range = 0;
4528 					}
4529 				} else if (ssa_op && info->ssa.var_info && ssa_op->op1_use >= 0) {
4530 					if (info->ssa.var_info[ssa_op->op1_use].has_range) {
4531 						if (tmp_has_range < 0) {
4532 							tmp_has_range = 1;
4533 							tmp_range = info->ssa.var_info[ssa_op->op1_use].range;
4534 						} else if (tmp_has_range) {
4535 							/* union */
4536 							if (info->ssa.var_info[ssa_op->op1_use].range.underflow) {
4537 								tmp_range.underflow = 1;
4538 								tmp_range.min = ZEND_LONG_MIN;
4539 							} else {
4540 								tmp_range.min = MIN(tmp_range.min, info->ssa.var_info[ssa_op->op1_use].range.min);
4541 							}
4542 							if (info->ssa.var_info[ssa_op->op1_use].range.overflow) {
4543 								tmp_range.overflow = 1;
4544 								tmp_range.max = ZEND_LONG_MAX;
4545 							} else {
4546 								tmp_range.max = MAX(tmp_range.max, info->ssa.var_info[ssa_op->op1_use].range.max);
4547 							}
4548 						}
4549 					} else if (!widening) {
4550 						tmp_has_range = 1;
4551 						tmp_range.underflow = 1;
4552 						tmp_range.min = ZEND_LONG_MIN;
4553 						tmp_range.max = ZEND_LONG_MAX;
4554 						tmp_range.overflow = 1;
4555 					}
4556 				} else {
4557 					tmp_has_range = 0;
4558 				}
4559 			}
4560 		}
4561 	}
4562 
4563 	if (!(op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
4564 		if (tmp_is_instanceof < 0) {
4565 			tmp_is_instanceof = 0;
4566 			tmp_ce = NULL;
4567 		}
4568 		if (tmp_has_range < 0) {
4569 			tmp_has_range = 0;
4570 		}
4571 		ret->ce = tmp_ce;
4572 		ret->is_instanceof = tmp_is_instanceof;
4573 	}
4574 	ret->type &= tmp;
4575 	ret->range = tmp_range;
4576 	ret->has_range = tmp_has_range;
4577 }
4578 
zend_infer_types(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_long optimization_level)4579 static zend_result zend_infer_types(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
4580 {
4581 	int ssa_vars_count = ssa->vars_count;
4582 	int j;
4583 	zend_bitset worklist;
4584 	ALLOCA_FLAG(use_heap);
4585 
4586 	worklist = do_alloca(sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count), use_heap);
4587 	memset(worklist, 0, sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count));
4588 
4589 	/* Type Inference */
4590 	for (j = op_array->last_var; j < ssa_vars_count; j++) {
4591 		zend_bitset_incl(worklist, j);
4592 	}
4593 
4594 	if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) == FAILURE) {
4595 		free_alloca(worklist,  use_heap);
4596 		return FAILURE;
4597 	}
4598 
4599 	if (optimization_level & ZEND_OPTIMIZER_NARROW_TO_DOUBLE) {
4600 		/* Narrowing integer initialization to doubles */
4601 		zend_type_narrowing(op_array, script, ssa, optimization_level);
4602 	}
4603 
4604 	if (ZEND_FUNC_INFO(op_array)) {
4605 		zend_func_return_info(op_array, script, 1, 0, &ZEND_FUNC_INFO(op_array)->return_info);
4606 	}
4607 
4608 	free_alloca(worklist,  use_heap);
4609 	return SUCCESS;
4610 }
4611 
zend_mark_cv_references(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa)4612 static void zend_mark_cv_references(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa)
4613 {
4614 	int var, def;
4615 	const zend_op *opline;
4616 	zend_arg_info *arg_info;
4617 	uint32_t worklist_len = zend_bitset_len(ssa->vars_count);
4618 	zend_bitset worklist;
4619 	ALLOCA_FLAG(use_heap);
4620 
4621 	worklist = do_alloca(sizeof(zend_ulong) * worklist_len, use_heap);
4622 	memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
4623 
4624 	/* Collect SSA variables which definitions creates PHP reference */
4625 	for (var = 0; var < ssa->vars_count; var++) {
4626 		def = ssa->vars[var].definition;
4627 		if (def >= 0 && ssa->vars[var].var < op_array->last_var) {
4628 			opline = op_array->opcodes + def;
4629 			if (ssa->ops[def].result_def == var) {
4630 				switch (opline->opcode) {
4631 					case ZEND_RECV:
4632 					case ZEND_RECV_INIT:
4633 						arg_info = &op_array->arg_info[opline->op1.num-1];
4634 						if (!ZEND_ARG_SEND_MODE(arg_info)) {
4635 							continue;
4636 						}
4637 						break;
4638 					default:
4639 						continue;
4640 				}
4641 			} else if (ssa->ops[def].op1_def == var) {
4642 				switch (opline->opcode) {
4643 					case ZEND_ASSIGN_REF:
4644 					case ZEND_MAKE_REF:
4645 					case ZEND_FE_RESET_RW:
4646 					case ZEND_BIND_GLOBAL:
4647 					case ZEND_SEND_REF:
4648 					case ZEND_SEND_VAR_EX:
4649 					case ZEND_SEND_FUNC_ARG:
4650 					case ZEND_BIND_INIT_STATIC_OR_JMP:
4651 						break;
4652 					case ZEND_INIT_ARRAY:
4653 					case ZEND_ADD_ARRAY_ELEMENT:
4654 						if (!(opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
4655 							continue;
4656 						}
4657 						break;
4658 					case ZEND_BIND_STATIC:
4659 						if (!(opline->extended_value & ZEND_BIND_REF)) {
4660 							continue;
4661 						}
4662 						break;
4663 					case ZEND_YIELD:
4664 						if (!(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
4665 							continue;
4666 						}
4667 						break;
4668 					case ZEND_OP_DATA:
4669 						switch ((opline-1)->opcode) {
4670 							case ZEND_ASSIGN_OBJ_REF:
4671 							case ZEND_ASSIGN_STATIC_PROP_REF:
4672 								break;
4673 							default:
4674 								continue;
4675 						}
4676 						break;
4677 					default:
4678 						continue;
4679 				}
4680 			} else if (ssa->ops[def].op2_def == var) {
4681 				switch (opline->opcode) {
4682 					case ZEND_ASSIGN_REF:
4683 					case ZEND_FE_FETCH_RW:
4684 						break;
4685 					case ZEND_BIND_LEXICAL:
4686 						if (!(opline->extended_value & ZEND_BIND_REF)) {
4687 							continue;
4688 						}
4689 						break;
4690 					default:
4691 						continue;
4692 				}
4693 			} else {
4694 				ZEND_UNREACHABLE();
4695 			}
4696 			zend_bitset_incl(worklist, var);
4697 		} else if (ssa->var_info[var].type & MAY_BE_REF) {
4698 			zend_bitset_incl(worklist, var);
4699 		} else if (ssa->vars[var].alias == SYMTABLE_ALIAS) {
4700 			zend_bitset_incl(worklist, var);
4701 		}
4702 	}
4703 
4704 	/* Set and propagate MAY_BE_REF */
4705 	WHILE_WORKLIST(worklist, worklist_len, var) {
4706 
4707 		ssa->var_info[var].type |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
4708 
4709 		if (ssa->vars[var].phi_use_chain) {
4710 			zend_ssa_phi *p = ssa->vars[var].phi_use_chain;
4711 			do {
4712 				if (!(ssa->var_info[p->ssa_var].type & MAY_BE_REF)) {
4713 					zend_bitset_incl(worklist, p->ssa_var);
4714 				}
4715 				p = zend_ssa_next_use_phi(ssa, var, p);
4716 			} while (p);
4717 		}
4718 
4719 		if (ssa->vars[var].use_chain >= 0) {
4720 			int use = ssa->vars[var].use_chain;
4721 			FOREACH_USE(&ssa->vars[var], use) {
4722 				zend_ssa_op *op = ssa->ops + use;
4723 				if (op->op1_use == var && op->op1_def >= 0) {
4724 					if (!(ssa->var_info[op->op1_def].type & MAY_BE_REF)) {
4725 						/* Unset breaks references (outside global scope). */
4726 						if (op_array->opcodes[use].opcode == ZEND_UNSET_CV
4727 								&& op_array->function_name) {
4728 							continue;
4729 						}
4730 						zend_bitset_incl(worklist, op->op1_def);
4731 					}
4732 				}
4733 				if (op->op2_use == var && op->op2_def >= 0) {
4734 					if (!(ssa->var_info[op->op2_def].type & MAY_BE_REF)) {
4735 						zend_bitset_incl(worklist, op->op2_def);
4736 					}
4737 				}
4738 				if (op->result_use == var && op->result_def >= 0) {
4739 					if (!(ssa->var_info[op->result_def].type & MAY_BE_REF)) {
4740 						zend_bitset_incl(worklist, op->result_def);
4741 					}
4742 				}
4743 			} FOREACH_USE_END();
4744 		}
4745 	} WHILE_WORKLIST_END();
4746 
4747 	free_alloca(worklist,  use_heap);
4748 }
4749 
zend_ssa_inference(zend_arena ** arena,const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_long optimization_level)4750 ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level) /* {{{ */
4751 {
4752 	zend_ssa_var_info *ssa_var_info;
4753 	int i;
4754 
4755 	if (!ssa->var_info) {
4756 		ssa->var_info = zend_arena_calloc(arena, ssa->vars_count, sizeof(zend_ssa_var_info));
4757 	}
4758 	ssa_var_info = ssa->var_info;
4759 
4760 	if (!op_array->function_name) {
4761 		for (i = 0; i < op_array->last_var; i++) {
4762 			ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
4763 			ssa_var_info[i].has_range = 0;
4764 		}
4765 	} else {
4766 		for (i = 0; i < op_array->last_var; i++) {
4767 			ssa_var_info[i].type = MAY_BE_UNDEF;
4768 			ssa_var_info[i].has_range = 0;
4769 			if (ssa->vars[i].alias) {
4770 				ssa_var_info[i].type |= get_ssa_alias_types(ssa->vars[i].alias);
4771 			}
4772 		}
4773 	}
4774 	for (i = op_array->last_var; i < ssa->vars_count; i++) {
4775 		ssa_var_info[i].type = 0;
4776 		ssa_var_info[i].has_range = 0;
4777 	}
4778 
4779 	zend_mark_cv_references(op_array, script, ssa);
4780 
4781 	zend_infer_ranges(op_array, ssa);
4782 
4783 	if (zend_infer_types(op_array, script, ssa, optimization_level) == FAILURE) {
4784 		return FAILURE;
4785 	}
4786 
4787 	return SUCCESS;
4788 }
4789 /* }}} */
4790 
zend_may_throw_ex(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,const zend_ssa * ssa,uint32_t t1,uint32_t t2)4791 ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa, uint32_t t1, uint32_t t2)
4792 {
4793 	if (opline->op1_type == IS_CV) {
4794 		if (t1 & MAY_BE_UNDEF) {
4795 			switch (opline->opcode) {
4796 				case ZEND_UNSET_VAR:
4797 				case ZEND_ISSET_ISEMPTY_VAR:
4798 					return 1;
4799 				case ZEND_ISSET_ISEMPTY_DIM_OBJ:
4800 				case ZEND_ISSET_ISEMPTY_PROP_OBJ:
4801 				case ZEND_ASSIGN:
4802 				case ZEND_ASSIGN_DIM:
4803 				case ZEND_ASSIGN_REF:
4804 				case ZEND_BIND_GLOBAL:
4805 				case ZEND_BIND_STATIC:
4806 				case ZEND_BIND_INIT_STATIC_OR_JMP:
4807 				case ZEND_FETCH_DIM_IS:
4808 				case ZEND_FETCH_OBJ_IS:
4809 				case ZEND_SEND_REF:
4810 				case ZEND_UNSET_CV:
4811 				case ZEND_ISSET_ISEMPTY_CV:
4812 				case ZEND_MAKE_REF:
4813 				case ZEND_FETCH_DIM_W:
4814 					break;
4815 				default:
4816 					/* undefined variable warning */
4817 					return 1;
4818 			}
4819 		}
4820 	} else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
4821 		if ((t1 & MAY_BE_RC1)
4822 		 && (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
4823 			switch (opline->opcode) {
4824 				case ZEND_CASE:
4825 				case ZEND_CASE_STRICT:
4826 				case ZEND_FE_FETCH_R:
4827 				case ZEND_FE_FETCH_RW:
4828 				case ZEND_FETCH_LIST_R:
4829 				case ZEND_QM_ASSIGN:
4830 				case ZEND_SEND_VAL:
4831 				case ZEND_SEND_VAL_EX:
4832 				case ZEND_SEND_VAR:
4833 				case ZEND_SEND_VAR_EX:
4834 				case ZEND_SEND_FUNC_ARG:
4835 				case ZEND_SEND_VAR_NO_REF:
4836 				case ZEND_SEND_VAR_NO_REF_EX:
4837 				case ZEND_SEND_REF:
4838 				case ZEND_SEPARATE:
4839 				case ZEND_END_SILENCE:
4840 				case ZEND_MAKE_REF:
4841 					break;
4842 				default:
4843 					/* destructor may be called */
4844 					return 1;
4845 			}
4846 		}
4847 	}
4848 
4849 	if (opline->op2_type == IS_CV) {
4850 		if (t2 & MAY_BE_UNDEF) {
4851 			switch (opline->opcode) {
4852 				case ZEND_ASSIGN_REF:
4853 				case ZEND_FE_FETCH_R:
4854 				case ZEND_FE_FETCH_RW:
4855 					break;
4856 				default:
4857 					/* undefined variable warning */
4858 					return 1;
4859 			}
4860 		}
4861 	} else if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
4862 		if ((t2 & MAY_BE_RC1)
4863 		 && (t2 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
4864 			switch (opline->opcode) {
4865 				case ZEND_ASSIGN:
4866 				case ZEND_FE_FETCH_R:
4867 				case ZEND_FE_FETCH_RW:
4868 					break;
4869 				default:
4870 					/* destructor may be called */
4871 					return 1;
4872 			}
4873 		}
4874 	}
4875 
4876 	switch (opline->opcode) {
4877 		case ZEND_NOP:
4878 		case ZEND_IS_IDENTICAL:
4879 		case ZEND_IS_NOT_IDENTICAL:
4880 		case ZEND_QM_ASSIGN:
4881 		case ZEND_JMP:
4882 		case ZEND_CHECK_VAR:
4883 		case ZEND_MAKE_REF:
4884 		case ZEND_BEGIN_SILENCE:
4885 		case ZEND_END_SILENCE:
4886 		case ZEND_FREE:
4887 		case ZEND_FE_FREE:
4888 		case ZEND_SEPARATE:
4889 		case ZEND_TYPE_CHECK:
4890 		case ZEND_DEFINED:
4891 		case ZEND_ISSET_ISEMPTY_THIS:
4892 		case ZEND_COALESCE:
4893 		case ZEND_SWITCH_LONG:
4894 		case ZEND_SWITCH_STRING:
4895 		case ZEND_MATCH:
4896 		case ZEND_ISSET_ISEMPTY_VAR:
4897 		case ZEND_ISSET_ISEMPTY_CV:
4898 		case ZEND_FUNC_NUM_ARGS:
4899 		case ZEND_FUNC_GET_ARGS:
4900 		case ZEND_COPY_TMP:
4901 		case ZEND_CASE_STRICT:
4902 		case ZEND_JMP_NULL:
4903 			return 0;
4904 		case ZEND_SEND_VAR:
4905 		case ZEND_SEND_VAL:
4906 		case ZEND_SEND_REF:
4907 		case ZEND_SEND_VAR_EX:
4908 		case ZEND_SEND_FUNC_ARG:
4909 		case ZEND_CHECK_FUNC_ARG:
4910 			/* May throw for named params. */
4911 			return opline->op2_type == IS_CONST;
4912 		case ZEND_INIT_FCALL:
4913 			/* can't throw, because call is resolved at compile time */
4914 			return 0;
4915 		case ZEND_BIND_GLOBAL:
4916 			if ((opline+1)->opcode == ZEND_BIND_GLOBAL) {
4917 				return zend_may_throw(opline + 1, ssa_op ? ssa_op + 1 : NULL, op_array, ssa);
4918 			}
4919 			return 0;
4920 		case ZEND_ADD:
4921 			if ((t1 & MAY_BE_ANY) == MAY_BE_ARRAY
4922 			 && (t2 & MAY_BE_ANY) == MAY_BE_ARRAY) {
4923 				return 0;
4924 			}
4925 			return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4926 				(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4927 		case ZEND_DIV:
4928 			if (!OP2_HAS_RANGE() ||
4929 				(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
4930 				/* Division by zero */
4931 				return 1;
4932 			}
4933 			ZEND_FALLTHROUGH;
4934 		case ZEND_SUB:
4935 		case ZEND_MUL:
4936 		case ZEND_POW:
4937 			return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4938 				(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4939 		/* Ops may throw if not an integer */
4940 		case ZEND_MOD:
4941 			if (!OP2_HAS_RANGE() ||
4942 				(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
4943 				/* Division by zero */
4944 				return 1;
4945 			}
4946 			ZEND_FALLTHROUGH;
4947 		case ZEND_SL:
4948 		case ZEND_SR:
4949 			return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4950 				(t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4951 				!OP2_HAS_RANGE() ||
4952 				OP2_MIN_RANGE() < 0;
4953 		case ZEND_CONCAT:
4954 		case ZEND_FAST_CONCAT:
4955 			return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) ||
4956 				(t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
4957 		case ZEND_BW_OR:
4958 		case ZEND_BW_AND:
4959 		case ZEND_BW_XOR:
4960 			if ((t1 & MAY_BE_ANY) == MAY_BE_STRING
4961 			 && (t2 & MAY_BE_ANY) == MAY_BE_STRING) {
4962 				return 0;
4963 			}
4964 			return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4965 				(t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4966 		case ZEND_BW_NOT:
4967 			return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4968 		case ZEND_PRE_INC:
4969 		case ZEND_POST_INC:
4970 			return (t1 & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4971 		/* null emits a warning as it has no effect compared to ++ which converts the value to 1 */
4972 		case ZEND_PRE_DEC:
4973 		case ZEND_POST_DEC:
4974 			return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4975 		case ZEND_BOOL_NOT:
4976 		case ZEND_JMPZ:
4977 		case ZEND_JMPNZ:
4978 		case ZEND_JMPZ_EX:
4979 		case ZEND_JMPNZ_EX:
4980 		case ZEND_BOOL:
4981 		case ZEND_JMP_SET:
4982 			return (t1 & MAY_BE_OBJECT);
4983 		case ZEND_BOOL_XOR:
4984 			return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_OBJECT);
4985 		case ZEND_IS_EQUAL:
4986 		case ZEND_IS_NOT_EQUAL:
4987 		case ZEND_IS_SMALLER:
4988 		case ZEND_IS_SMALLER_OR_EQUAL:
4989 		case ZEND_CASE:
4990 		case ZEND_SPACESHIP:
4991 			if ((t1 & MAY_BE_ANY) == MAY_BE_NULL
4992 			 || (t2 & MAY_BE_ANY) == MAY_BE_NULL) {
4993 				return 0;
4994 			}
4995 			return (t1 & (MAY_BE_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT)) || (t2 & (MAY_BE_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT));
4996 		case ZEND_ASSIGN_OP:
4997 			if (opline->extended_value == ZEND_ADD) {
4998 				if ((t1 & MAY_BE_ANY) == MAY_BE_ARRAY
4999 				 && (t2 & MAY_BE_ANY) == MAY_BE_ARRAY) {
5000 					return 0;
5001 				}
5002 				return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
5003 					(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5004 			} else if (opline->extended_value == ZEND_DIV ||
5005 				opline->extended_value == ZEND_MOD) {
5006 				if (!OP2_HAS_RANGE() ||
5007 					(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
5008 					/* Division by zero */
5009 					return 1;
5010 				}
5011 				return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
5012 					(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5013 			} else if (opline->extended_value == ZEND_SUB ||
5014 				opline->extended_value == ZEND_MUL ||
5015 				opline->extended_value == ZEND_POW) {
5016 				return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
5017 					(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5018 			} else if (opline->extended_value == ZEND_SL ||
5019 				opline->extended_value == ZEND_SR) {
5020 				return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
5021 					(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
5022 					!OP2_HAS_RANGE() ||
5023 					OP2_MIN_RANGE() < 0;
5024 			} else if (opline->extended_value == ZEND_CONCAT) {
5025 				return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) ||
5026 					(t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
5027 			} else if (opline->extended_value == ZEND_BW_OR ||
5028 				opline->extended_value == ZEND_BW_AND ||
5029 				opline->extended_value == ZEND_BW_XOR) {
5030 				if ((t1 & MAY_BE_ANY) == MAY_BE_STRING
5031 				 && (t2 & MAY_BE_ANY) == MAY_BE_STRING) {
5032 					return 0;
5033 				}
5034 				return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
5035 					(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5036 			}
5037 			return 1;
5038 		case ZEND_ASSIGN:
5039 			if (t1 & MAY_BE_REF) {
5040 				return 1;
5041 			}
5042 			ZEND_FALLTHROUGH;
5043 		case ZEND_UNSET_VAR:
5044 			return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY));
5045 		case ZEND_BIND_STATIC:
5046 		case ZEND_BIND_INIT_STATIC_OR_JMP:
5047 			if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) {
5048 				/* Destructor may throw. */
5049 				return 1;
5050 			}
5051 			return 0;
5052 		case ZEND_ASSIGN_DIM:
5053 			if ((opline+1)->op1_type == IS_CV) {
5054 				if (_ssa_op1_info(op_array, ssa, opline+1, ssa_op+1) & MAY_BE_UNDEF) {
5055 					return 1;
5056 				}
5057 			}
5058 			if (t1 & (MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_REF)) {
5059 				return 1;
5060 			}
5061 			return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED ||
5062 				(t2 & (MAY_BE_UNDEF|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5063 		case ZEND_ASSIGN_OBJ:
5064 			if (t1 & (MAY_BE_ANY-MAY_BE_OBJECT)) {
5065 				return 1;
5066 			}
5067 			if ((opline+1)->op1_type == IS_CV) {
5068 				if (_ssa_op1_info(op_array, ssa, opline+1, ssa_op+1) & MAY_BE_UNDEF) {
5069 					return 1;
5070 				}
5071 			}
5072 			if (ssa_op->op1_use) {
5073 				const zend_ssa_var_info *var_info = ssa->var_info + ssa_op->op1_use;
5074 				const zend_class_entry *ce = var_info->ce;
5075 
5076 				if (var_info->is_instanceof
5077 				 || !ce
5078 				 || ce->create_object
5079 				 || ce->default_object_handlers->write_property != zend_std_write_property
5080 				 || ce->default_object_handlers->get_property_ptr_ptr != zend_std_get_property_ptr_ptr
5081 				 || ce->__get
5082 				 || ce->__set
5083 				 || ce->parent) {
5084 					return 1;
5085 				}
5086 
5087 				if (opline->op2_type != IS_CONST) {
5088 					return 1;
5089 				}
5090 
5091 				zend_string *prop_name = Z_STR_P(CRT_CONSTANT(opline->op2));
5092 				if (ZSTR_LEN(prop_name) > 0 && ZSTR_VAL(prop_name)[0] == '\0') {
5093 					return 1;
5094 				}
5095 
5096 				zend_property_info *prop_info =
5097 					zend_hash_find_ptr(&ce->properties_info, prop_name);
5098 				if (prop_info) {
5099 					if (ZEND_TYPE_IS_SET(prop_info->type)) {
5100 						return 1;
5101 					}
5102 					return !(prop_info->flags & ZEND_ACC_PUBLIC)
5103 						&& prop_info->ce != op_array->scope;
5104 				} else {
5105 					return !(ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES);
5106 				}
5107 			}
5108 			return 1;
5109 		case ZEND_ROPE_INIT:
5110 		case ZEND_ROPE_ADD:
5111 		case ZEND_ROPE_END:
5112 			return t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT);
5113 		case ZEND_INIT_ARRAY:
5114 			return (opline->op2_type != IS_UNUSED) && (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5115 		case ZEND_ADD_ARRAY_ELEMENT:
5116 			return (opline->op2_type == IS_UNUSED) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5117 		case ZEND_STRLEN:
5118 			return (t1 & MAY_BE_ANY) != MAY_BE_STRING;
5119 		case ZEND_COUNT:
5120 			return (t1 & MAY_BE_ANY) != MAY_BE_ARRAY;
5121 		case ZEND_RECV_INIT:
5122 			if (Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_CONSTANT_AST) {
5123 				return 1;
5124 			}
5125 			if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
5126 				uint32_t arg_num = opline->op1.num;
5127 				const zend_arg_info *cur_arg_info;
5128 
5129 				if (EXPECTED(arg_num <= op_array->num_args)) {
5130 					cur_arg_info = &op_array->arg_info[arg_num-1];
5131 				} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
5132 					cur_arg_info = &op_array->arg_info[op_array->num_args];
5133 				} else {
5134 					return 0;
5135 				}
5136 				return ZEND_TYPE_IS_SET(cur_arg_info->type);
5137 			} else {
5138 				return 0;
5139 			}
5140 		case ZEND_FETCH_IS:
5141 			return (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
5142 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
5143 			return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT));
5144 		case ZEND_FETCH_DIM_IS:
5145 			return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5146 		case ZEND_CAST:
5147 			switch (opline->extended_value) {
5148 				case IS_LONG:
5149 				case IS_DOUBLE:
5150 					return (t1 & MAY_BE_OBJECT);
5151 				case IS_STRING:
5152 					return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
5153 				case IS_ARRAY:
5154 					return (t1 & MAY_BE_OBJECT);
5155 				case IS_OBJECT:
5156 					return 0;
5157 				EMPTY_SWITCH_DEFAULT_CASE()
5158 			}
5159 			/* GCC is getting confused here for the Wimplicit-fallthrough warning with
5160 			 * EMPTY_SWITCH_DEFAULT_CASE() macro */
5161 			return 0;
5162 		case ZEND_ARRAY_KEY_EXISTS:
5163 			if ((t2 & MAY_BE_ANY) != MAY_BE_ARRAY) {
5164 				return 1;
5165 			}
5166 			if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
5167 				return 1;
5168 			}
5169 			return 0;
5170 		case ZEND_FE_RESET_R:
5171 		case ZEND_FE_RESET_RW:
5172 			if ((t1 & (MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
5173 				return 1;
5174 			}
5175 			return 0;
5176 		case ZEND_FE_FETCH_R:
5177 			if ((t1 & (MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
5178 				return 1;
5179 			}
5180 			if (opline->op2_type == IS_CV
5181 			 && (t2 & MAY_BE_RC1)
5182 			 && (t2 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
5183 				return 1;
5184 			}
5185 			return 0;
5186 		case ZEND_FETCH_DIM_W:
5187 		case ZEND_FETCH_LIST_W:
5188 			if (t1 & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
5189 				return 1;
5190 			}
5191 			if (t2 & (MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
5192 				return 1;
5193 			}
5194 			if (opline->op2_type == IS_UNUSED) {
5195 				return 1;
5196 			}
5197 			return 0;
5198 		default:
5199 			return 1;
5200 	}
5201 }
5202 
zend_may_throw(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,const zend_ssa * ssa)5203 ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa)
5204 {
5205 	return zend_may_throw_ex(opline, ssa_op, op_array, ssa, OP1_INFO(), OP2_INFO());
5206 }
5207