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