diff options
author | Bob Weinand <bobwei9@hotmail.com> | 2018-03-09 15:08:14 +0100 |
---|---|---|
committer | Bob Weinand <bobwei9@hotmail.com> | 2018-03-10 15:20:45 +0100 |
commit | 9c6df8a238c4492704d9f37d2a155cf85d704804 (patch) | |
tree | a1dda1952b0aea68308be86d0c9a9443ddf74310 | |
parent | 8417a239731158b7a8585f323e2c9216cac13c85 (diff) | |
download | php-git-9c6df8a238c4492704d9f37d2a155cf85d704804.tar.gz |
Fix bug #76074 (opcache corrupts variable in for-loop)
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 37 | ||||
-rw-r--r-- | ext/opcache/tests/bug76074.phpt | 16 |
3 files changed, 50 insertions, 6 deletions
@@ -11,6 +11,9 @@ PHP NEWS - GD: . Fixed bug #73957 (signed integer conversion in imagescale()). (cmb) +- Opcache: + . Fixed bug #76074 (opcache corrupts variable in for-loop). (Bob) + 01 Mar 2018, PHP 7.1.15 - Apache2Handler: diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index aeb30c8ec5..9f930a1ab6 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -157,6 +157,17 @@ } \ } while (0) +static inline zend_bool add_will_overflow(zend_long a, zend_long b) { + return (b > 0 && a > ZEND_LONG_MAX - b) + || (b < 0 && a < ZEND_LONG_MIN - b); +} +#if 0 +static inline zend_bool sub_will_overflow(zend_long a, zend_long b) { + return (b > 0 && a < ZEND_LONG_MIN + b) + || (b < 0 && a > ZEND_LONG_MAX + b); +} +#endif + 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) /* {{{ */ { #ifdef SYM_RANGE @@ -826,7 +837,9 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int #ifdef SYM_RANGE } else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) { tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow && tmp->underflow; - tmp->min = MAX(ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min, tmp->min); + if (!add_will_overflow(ssa->var_info[constraint->min_ssa_var].range.min, constraint->range.min)) { + tmp->min = MAX(ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min, tmp->min); + } #endif } if (constraint->max_ssa_var < 0) { @@ -834,7 +847,9 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->overflow = constraint->range.overflow && tmp->overflow; #ifdef SYM_RANGE } else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) { - tmp->max = MIN(ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max, tmp->max); + if (!add_will_overflow(ssa->var_info[constraint->max_ssa_var].range.max, constraint->range.max)) { + tmp->max = MIN(ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max, tmp->max); + } tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow && tmp->overflow; #endif } @@ -844,8 +859,13 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->min = constraint->range.min; #ifdef SYM_RANGE } else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) { - tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow; - tmp->min = ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min; + if (add_will_overflow(ssa->var_info[constraint->min_ssa_var].range.min, constraint->range.min)) { + tmp->underflow = 1; + tmp->min = ZEND_LONG_MIN; + } else { + tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow; + tmp->min = ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min; + } #endif } else { tmp->underflow = 1; @@ -856,8 +876,13 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->overflow = constraint->range.overflow; #ifdef SYM_RANGE } else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) { - tmp->max = ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max; - tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow; + if (add_will_overflow(ssa->var_info[constraint->max_ssa_var].range.max, constraint->range.max)) { + tmp->overflow = 1; + tmp->max = ZEND_LONG_MAX; + } else { + tmp->max = ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max; + tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow; + } #endif } else { tmp->max = ZEND_LONG_MAX; diff --git a/ext/opcache/tests/bug76074.phpt b/ext/opcache/tests/bug76074.phpt new file mode 100644 index 0000000000..b6ad7cb587 --- /dev/null +++ b/ext/opcache/tests/bug76074.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #76074 (opcache corrupts variable in for-loop) +--FILE-- +<?php + +function test(int $nr) { + for ($i = $nr; $i <= $nr + 1; $i++) + var_dump($i); +} + +test(1); + +?> +--EXPECT-- +int(1) +int(2) |