summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Weinand <bobwei9@hotmail.com>2018-03-09 15:08:14 +0100
committerBob Weinand <bobwei9@hotmail.com>2018-03-10 15:20:45 +0100
commit9c6df8a238c4492704d9f37d2a155cf85d704804 (patch)
treea1dda1952b0aea68308be86d0c9a9443ddf74310
parent8417a239731158b7a8585f323e2c9216cac13c85 (diff)
downloadphp-git-9c6df8a238c4492704d9f37d2a155cf85d704804.tar.gz
Fix bug #76074 (opcache corrupts variable in for-loop)
-rw-r--r--NEWS3
-rw-r--r--ext/opcache/Optimizer/zend_inference.c37
-rw-r--r--ext/opcache/tests/bug76074.phpt16
3 files changed, 50 insertions, 6 deletions
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--
+<?php
+
+function test(int $nr) {
+ for ($i = $nr; $i <= $nr + 1; $i++)
+ var_dump($i);
+}
+
+test(1);
+
+?>
+--EXPECT--
+int(1)
+int(2)