PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/opcache/Optimizer - zend_inference.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1232 2359 52.2 %
Date: 2018-09-10 Functions: 33 47 70.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 10 Sep 2018 14:11:41 +0000 (10 days ago)

Copyright © 2005-2018 The PHP Group
All rights reserved.