Skip to content

Commit cc6498d

Browse files
committed
Fix memory leak in by-ref foreach.
The issue occurs if a circular reference on the array var of a by-ref foreach is created, all visible references to the array var are removed and the garbage collector is invoked before exiting the foreach. Invoking the garbage collector removes the array var from the roots, because the foreach statement itself is still holding a reference to it and thus it's still alive, but when the foreach ends it does not re-add the array var to the GC roots, thus the GC cannot collect it and it leaks. This PR fixes the issue by invoking the GC-aware zval destructor, which correctly adds the zval to the GC roots. Fixes oss-fuzz #54515.
1 parent 5f46d86 commit cc6498d

File tree

4 files changed

+21
-2
lines changed

4 files changed

+21
-2
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ PHP NEWS
55
- Core:
66
. Fixed bug GH-12468 (Double-free of doc_comment when overriding static
77
property via trait). (ilutov)
8+
. Fix memory leak if a circular reference is created inside a by-ref foreach
9+
on the array variable. (danog)
810

911
- DOM:
1012
. Fix registerNodeClass with abstract class crashing. (nielsdos)

Zend/tests/leak_foreach_on_ref.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Fix memory leak if a circular reference is created inside a by-ref foreach on the array variable.
3+
--FILE--
4+
<?php
5+
6+
$a = [0];
7+
8+
foreach ($a as &$v) {
9+
$a[0] = &$a;
10+
unset($a);
11+
gc_collect_cycles();
12+
}
13+
14+
?>
15+
==DONE==
16+
--EXPECT--
17+
==DONE==

Zend/zend_vm_def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3125,7 +3125,7 @@ ZEND_VM_HOT_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
31253125
if (Z_FE_ITER_P(var) != (uint32_t)-1) {
31263126
zend_hash_iterator_del(Z_FE_ITER_P(var));
31273127
}
3128-
zval_ptr_dtor_nogc(var);
3128+
zval_ptr_dtor(var);
31293129
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
31303130
}
31313131

Zend/zend_vm_execute.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14317,7 +14317,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVA
1431714317
if (Z_FE_ITER_P(var) != (uint32_t)-1) {
1431814318
zend_hash_iterator_del(Z_FE_ITER_P(var));
1431914319
}
14320-
zval_ptr_dtor_nogc(var);
14320+
zval_ptr_dtor(var);
1432114321
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
1432214322
}
1432314323

0 commit comments

Comments
 (0)