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