From 9c6df8a238c4492704d9f37d2a155cf85d704804 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 9 Mar 2018 15:08:14 +0100 Subject: Fix bug #76074 (opcache corrupts variable in for-loop) --- NEWS | 3 +++ ext/opcache/Optimizer/zend_inference.c | 37 ++++++++++++++++++++++++++++------ ext/opcache/tests/bug76074.phpt | 16 +++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 ext/opcache/tests/bug76074.phpt diff --git a/NEWS b/NEWS index 566494414f..dc12ec1ad2 100644 --- a/NEWS +++ b/NEWS @@ -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-- + +--EXPECT-- +int(1) +int(2) -- cgit v1.2.1