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