Skip to content

Commit 6282022

Browse files
committed
Fix leak with EXT_STMT when pipe result is unused
This example would leak: function x() { return range(0, 10); } function test($a, $b) { $a |> $b; } test(42, x(...)); because we were missing a FREE in test(). This requires two fixes, namely one in zend_do_free() to skip over the EXT_STMT usage, and another in zend_optimize_block() to avoid removing the FREE opcode by removing the result def of the declaring opcode.
1 parent 1eaa527 commit 6282022

File tree

2 files changed

+10
-1
lines changed

2 files changed

+10
-1
lines changed

Zend/Optimizer/block_pass.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,14 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
420420
}
421421
break;
422422

423+
case ZEND_EXT_STMT:
424+
if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
425+
/* Variable will be deleted later by FREE, so we can't optimize it */
426+
Tsource[VAR_NUM(opline->op1.var)] = NULL;
427+
break;
428+
}
429+
break;
430+
423431
case ZEND_CASE:
424432
case ZEND_CASE_STRICT:
425433
case ZEND_COPY_TMP:

Zend/zend_compile.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,8 @@ static void zend_do_free(znode *op1) /* {{{ */
821821
} else {
822822
while (opline >= CG(active_op_array)->opcodes) {
823823
if ((opline->opcode == ZEND_FETCH_LIST_R ||
824-
opline->opcode == ZEND_FETCH_LIST_W) &&
824+
opline->opcode == ZEND_FETCH_LIST_W ||
825+
opline->opcode == ZEND_EXT_STMT) &&
825826
opline->op1_type == IS_VAR &&
826827
opline->op1.var == op1->u.op.var) {
827828
zend_emit_op(NULL, ZEND_FREE, op1, NULL);

0 commit comments

Comments
 (0)