From fa1abb567798fb50a2d84e82021b79909c6aefba Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 2 Jul 2015 02:00:34 +0300 Subject: [PATCH] Fixed memory leak because of incorrect 'if ();' optimization --- ext/opcache/Optimizer/block_pass.c | 28 ++++++++++++++++++++++++ ext/opcache/Optimizer/pass3.c | 6 ------ ext/opcache/tests/leak_001.phpt | 34 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 ext/opcache/tests/leak_001.phpt diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index a8108296286..ee9bda6094c 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1403,6 +1403,34 @@ static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_arra break; } + if (block->op2_to == block->follow_to) { + /* L: JMPZ(X, L+1) -> NOP or FREE(X) */ + + if (last_op->op1_type == IS_VAR) { + zend_op **Tsource = cfg->Tsource; + zend_op *src = VAR_SOURCE(last_op->op1); + + if (src && + src->opcode != ZEND_FETCH_R && + src->opcode != ZEND_FETCH_DIM_R && + src->opcode != ZEND_FETCH_OBJ_R) { + ZEND_RESULT_TYPE(src) |= EXT_TYPE_UNUSED; + MAKE_NOP(last_op); + block->op2_to = NULL; + break; + } + } + if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) { + last_op->opcode = ZEND_FREE; + last_op->op2.num = 0; + block->op2_to = NULL; + } else { + MAKE_NOP(last_op); + block->op2_to = NULL; + } + break; + } + if (block->op2_to) { zend_uchar same_type = ZEND_OP1_TYPE(last_op); uint32_t same_var = VAR_NUM_EX(last_op->op1); diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c index cb717998d6e..3e589df6286 100644 --- a/ext/opcache/Optimizer/pass3.c +++ b/ext/opcache/Optimizer/pass3.c @@ -202,12 +202,6 @@ void zend_optimizer_pass3(zend_op_array *op_array) break; } - /* convert L: JMPZ L+1 to NOP */ - if (ZEND_OP2(opline).opline_num == opline_num + 1) { - MAKE_NOP(opline); - goto done_jmp_optimization; - } - while (ZEND_OP2(opline).opline_num < op_array->last) { int target = ZEND_OP2(opline).opline_num; diff --git a/ext/opcache/tests/leak_001.phpt b/ext/opcache/tests/leak_001.phpt new file mode 100644 index 00000000000..c590943fcbb --- /dev/null +++ b/ext/opcache/tests/leak_001.phpt @@ -0,0 +1,34 @@ +--TEST-- +Leak 001: Incorrect 'if ();' optimization +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache_only=0 +--SKIPIF-- + +--FILE-- + +OK +--EXPECT-- +OK