Skip to content

Commit bb283ee

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 bbfadd3 commit bb283ee

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
@@ -6,6 +6,8 @@ PHP NEWS
66
. Fixed bug GH-12468 (Double-free of doc_comment when overriding static
77
property via trait). (ilutov)
88
. Fixed segfault caused by weak references to FFI objects. (sj-i)
9+
. Fix memory leak if a circular reference is created inside a by-ref foreach
10+
on the array variable. (danog)
911

1012
- DOM:
1113
. 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)