summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c40
-rw-r--r--ext/opcache/tests/bug69038.phpt45
3 files changed, 79 insertions, 11 deletions
diff --git a/NEWS b/NEWS
index 0d93c47b02..9ae5f2294c 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,10 @@ PHP NEWS
. Added NULL byte protection to exec, system and passthru. (Yasuo)
- ODBC:
- . Bug #68964 (Allowed memory size exhausted with odbc_exec). (Anatol)
+ . Fixed bug #68964 (Allowed memory size exhausted with odbc_exec). (Anatol)
+
+- Opcache:
+ . Fixed bug #69038 (switch(SOMECONSTANT) misbehaves). (Laruence)
- OpenSSL:
. Fix bug #61285, #68329, #68046, #41631: encrypted streams don't observe
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 3ea648a537..7829ee7c95 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -291,17 +291,41 @@ static void replace_tmp_by_const(zend_op_array *op_array,
* usually terminated by ZEND_FREE that finally kills the value.
*/
if (opline->opcode == ZEND_CASE) {
- zval old_val;
- old_val = *val;
- zval_copy_ctor(val);
- update_op1_const(op_array, opline, val TSRMLS_CC);
- *val = old_val;
+ zend_op *m, *n;
+ int brk = op_array->last_brk_cont;
+ while (brk--) {
+ if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
+ op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
+ break;
+ }
+ }
+ m = opline;
+ n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
+ while (m < n) {
+ if (ZEND_OP1_TYPE(m) == IS_TMP_VAR &&
+ ZEND_OP1(m).var == var) {
+ if (m->opcode == ZEND_CASE) {
+ zval old_val;
+ old_val = *val;
+ zval_copy_ctor(val);
+ update_op1_const(op_array, m, val TSRMLS_CC);
+ *val = old_val;
+ } else if (m->opcode == ZEND_FREE) {
+ MAKE_NOP(m);
+ } else {
+ ZEND_ASSERT(0);
+ }
+ }
+ m++;
+ }
+ zval_dtor(val);
+ break;
} else if (opline->opcode == ZEND_FREE) {
MAKE_NOP(opline);
+ zval_dtor(val);
break;
} else {
update_op1_const(op_array, opline, val TSRMLS_CC);
- val = NULL;
break;
}
}
@@ -311,14 +335,10 @@ static void replace_tmp_by_const(zend_op_array *op_array,
update_op2_const(op_array, opline, val TSRMLS_CC);
/* TMP_VAR may be used only once */
- val = NULL;
break;
}
opline++;
}
- if (val) {
- zval_dtor(val);
- }
}
#include "Optimizer/nop_removal.c"
diff --git a/ext/opcache/tests/bug69038.phpt b/ext/opcache/tests/bug69038.phpt
new file mode 100644
index 0000000000..9aeecfeece
--- /dev/null
+++ b/ext/opcache/tests/bug69038.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Bug #69038 (switch(SOMECONSTANT) misbehaves)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function a($a = "bad") {
+
+ switch (PHP_OS) {
+ case "LALALALA" : return "LALALAL";
+ case PHP_OS: return "okey";
+ default: break;
+ }
+
+ return $a;
+}
+
+var_dump(a());
+
+
+function b($b = "bad") {
+ switch (PHP_OS) {
+ case "LALALAL": return "bad";
+ case PHP_OS:
+ switch (PHP_OS) {
+ case "FOO": break;
+ case PHP_OS: return "okey";
+ default :
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return $b;
+}
+var_dump(b());
+?>
+--EXPECT--
+string(4) "okey"
+string(4) "okey"