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