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