diff options
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 36 | ||||
-rw-r--r-- | ext/opcache/tests/bug69038.phpt | 56 |
2 files changed, 85 insertions, 7 deletions
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index a8506fb078..191e13ca1d 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -310,13 +310,35 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, * usually terminated by ZEND_FREE that finally kills the value. */ case ZEND_CASE: { - zval old_val; - ZVAL_COPY_VALUE(&old_val, val); - zval_copy_ctor(val); - zend_optimizer_update_op1_const(op_array, opline, val); - ZVAL_COPY_VALUE(val, &old_val); - opline++; - continue; + 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) == type && + ZEND_OP1(m).var == var) { + if (m->opcode == ZEND_CASE) { + zval old_val; + ZVAL_COPY_VALUE(&old_val, val); + zval_copy_ctor(val); + zend_optimizer_update_op1_const(op_array, m, val); + ZVAL_COPY_VALUE(val, &old_val); + } else if (m->opcode == ZEND_FREE) { + MAKE_NOP(m); + } else { + ZEND_ASSERT(0); + } + } + m++; + } + zval_dtor(val); + return 1; } case ZEND_FREE: MAKE_NOP(opline); diff --git a/ext/opcache/tests/bug69038.phpt b/ext/opcache/tests/bug69038.phpt new file mode 100644 index 0000000000..f0c54913c5 --- /dev/null +++ b/ext/opcache/tests/bug69038.phpt @@ -0,0 +1,56 @@ +--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()); + +function c($b = "bad") { + switch (extension_loaded("standard")) { + case 0 : return "LALALAL"; + case 1 : return "okey"; + default : return "bad"; + } +} +var_dump(c()); + +?> +--EXPECT-- +string(4) "okey" +string(4) "okey" +string(4) "okey" |