From 66d30959935da6ad3df800f45a2d23d09637054c Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 17 Feb 2015 11:34:57 +0800 Subject: [PATCH] Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) --- NEWS | 5 ++- ext/opcache/Optimizer/zend_optimizer.c | 40 +++++++++++++++++------ ext/opcache/tests/bug69038.phpt | 45 ++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 ext/opcache/tests/bug69038.phpt diff --git a/NEWS b/NEWS index 0d93c47b020..9ae5f2294ca 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 3ea648a5379..7829ee7c95b 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 00000000000..9aeecfeeceb --- /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-- + +--FILE-- + +--EXPECT-- +string(4) "okey" +string(4) "okey"