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