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