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