Skip to content

Commit 19be8b6

Browse files
committed
Fixed issue #183 (TMP_VAR is not only used once)
1 parent 980c636 commit 19be8b6

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

ext/opcache/Optimizer/zend_optimizer.c

+25-4
Original file line numberDiff line numberDiff line change
@@ -284,20 +284,41 @@ static void replace_tmp_by_const(zend_op_array *op_array,
284284
if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
285285
ZEND_OP1(opline).var == var) {
286286

287-
update_op1_const(op_array, opline, val TSRMLS_CC);
288-
/* TMP_VAR my be used only once */
289-
break;
287+
/* In most cases IS_TMP_VAR operand may be used only once.
288+
* The operands are usually destroyed by the opcode handler.
289+
* ZEND_CASE is an exception, that keeps operand unchanged,
290+
* and allows its reuse. The number of ZEND_CASE instructions
291+
* usually terminated by ZEND_FREE that finally kills the value.
292+
*/
293+
if (opline->opcode == ZEND_CASE) {
294+
zval old_val;
295+
old_val = *val;
296+
zval_copy_ctor(val);
297+
update_op1_const(op_array, opline, val TSRMLS_CC);
298+
*val = old_val;
299+
} else if (opline->opcode == ZEND_FREE) {
300+
MAKE_NOP(opline);
301+
break;
302+
} else {
303+
update_op1_const(op_array, opline, val TSRMLS_CC);
304+
val = NULL;
305+
break;
306+
}
290307
}
291308

292309
if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
293310
ZEND_OP2(opline).var == var) {
294311

295312
update_op2_const(op_array, opline, val TSRMLS_CC);
296-
/* TMP_VAR my be used only once */
313+
/* TMP_VAR may be used only once */
314+
val = NULL;
297315
break;
298316
}
299317
opline++;
300318
}
319+
if (val) {
320+
zval_dtor(val);
321+
}
301322
}
302323

303324
#include "Optimizer/nop_removal.c"

0 commit comments

Comments
 (0)