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