]> granicus.if.org Git - php/commitdiff
Make inference robust against infinite loop
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 23 Jun 2017 15:07:44 +0000 (17:07 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 23 Jun 2017 15:07:44 +0000 (17:07 +0200)
Right now, if narrowing occurs on non-debug builds, inference can
easily go into an infinite loop. Prevent this, and add a pointer
that this should be reported as a bug.

ext/opcache/Optimizer/zend_inference.c

index f572616567209634cf78f5b780d6d3d8cedbdba9..d6a4c273bd52a62c86640046345fbacb9d57ba79 100644 (file)
@@ -1753,8 +1753,11 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
                                }                                                       \
                        }                                                                                                                       \
                        if (ssa_var_info[__var].type != __type) {                                       \
-                               check_type_narrowing(op_array, ssa, worklist,                   \
-                                       __var, ssa_var_info[__var].type, __type);                       \
+                               if (ssa_var_info[__var].type & ~__type) {                               \
+                                       handle_type_narrowing(op_array, ssa, worklist,          \
+                                               __var, ssa_var_info[__var].type, __type);               \
+                                       return FAILURE;                                                                         \
+                               }                                                                                                               \
                                ssa_var_info[__var].type = __type;                                              \
                                add_usages(op_array, ssa, worklist, __var);                             \
                        }                                                                                                                       \
@@ -1891,15 +1894,17 @@ static void reset_dependent_vars(const zend_op_array *op_array, zend_ssa *ssa, z
 #endif
 }
 
-static void check_type_narrowing(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset worklist, int var, uint32_t old_type, uint32_t new_type)
+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)
 {
-       /* if new_type set resets some bits from old_type set
-        * We have completely recalculate types of some dependent SSA variables
-        * (this may occurs mainly because of incremental inter-precudure
-        * type inference)
-        */
-       if (old_type & ~new_type) {
-               ZEND_ASSERT(0); /* Currently this should never happen */
+       if (1) {
+               /* Right now, this is always a bug */
+               zend_error(E_WARNING, "Narrowing occurred during type inference. Please file a bug report on bugs.php.net");
+       } else {
+               /* if new_type set resets some bits from old_type set
+                * We have completely recalculate types of some dependent SSA variables
+                * (this may occurs mainly because of incremental inter-precudure
+                * type inference)
+                */
                reset_dependent_vars(op_array, ssa, worklist, var);
        }
 }
@@ -2125,7 +2130,7 @@ static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *ar
        return tmp;
 }
 
-static void zend_update_type_info(const zend_op_array *op_array,
+static int zend_update_type_info(const zend_op_array *op_array,
                                   zend_ssa            *ssa,
                                   const zend_script   *script,
                                   zend_bitset          worklist,
@@ -3219,6 +3224,8 @@ unknown_opcode:
                        }
                        break;
        }
+
+       return SUCCESS;
 }
 
 static uint32_t get_class_entry_rank(zend_class_entry *ce) {
@@ -3329,7 +3336,9 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script
                        }
                } else if (ssa_vars[j].definition >= 0) {
                        i = ssa_vars[j].definition;
-                       zend_update_type_info(op_array, ssa, script, worklist, i);
+                       if (zend_update_type_info(op_array, ssa, script, worklist, i) == FAILURE) {
+                               return FAILURE;
+                       }
                }
        } WHILE_WORKLIST_END();
        return SUCCESS;