Skip to content

Commit b15c597

Browse files
iliaalarnaud-lb
authored andcommitted
Fix GH-19983: GC assertion failure with fibers, generators and destructors
When GC runs inside a fiber handling an exception (e.g. during zend_fiber_object_destroy), EG(exception) is set. gc_call_destructors_in_fiber() saved and cleared the exception after creating the destructor fiber. Since zend_call_function() returns early when EG(exception) is set, the destructor fiber's handler never ran, leaving DTOR_GARBAGE entries in the root buffer. On the next GC cycle, gc_collect_roots() hit an alignment assertion on these stale entries. Move remember_prev_exception() before the destructor fiber creation/resume so EG(exception) is cleared before zend_call_function() runs inside the fiber. Closes GH-21529
1 parent cd568cb commit b15c597

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.21
44

5+
- Core:
6+
. Fixed bug GH-19983 (GC assertion failure with fibers, generators and
7+
destructors). (iliaal)
58

69
09 Apr 2026, PHP 8.4.20
710

Zend/tests/fibers/gh19983.phpt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GH-19983 (GC Assertion Failure with fibers, generators and destructors)
3+
--SKIPIF--
4+
<?php if (PHP_INT_SIZE < 8) die("skip 64-bit only - fiber stacks exhaust 32-bit address space"); ?>
5+
--INI--
6+
memory_limit=128M
7+
--FILE--
8+
<?php
9+
class a
10+
{
11+
function __destruct()
12+
{
13+
$gen = (function () {
14+
$from = (function () {
15+
$cv = [new a];
16+
Fiber::suspend();
17+
})();
18+
yield from $from;
19+
})();
20+
$fiber = new Fiber(function () use ($gen, &$fiber) {
21+
$gen->current();
22+
});
23+
$fiber->start();
24+
}
25+
}
26+
new a;
27+
?>
28+
--EXPECTF--
29+
Fatal error: Allowed memory size of %d bytes exhausted%s

Zend/zend_gc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1893,13 +1893,15 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end)
18931893
GC_G(dtor_idx) = GC_FIRST_ROOT;
18941894
GC_G(dtor_end) = GC_G(first_unused);
18951895

1896+
zend_object *exception = NULL;
1897+
remember_prev_exception(&exception);
1898+
18961899
if (UNEXPECTED(!fiber)) {
18971900
fiber = gc_create_destructor_fiber();
18981901
} else {
18991902
zend_fiber_resume(fiber, NULL, NULL);
19001903
}
19011904

1902-
zend_object *exception = NULL;
19031905
remember_prev_exception(&exception);
19041906

19051907
for (;;) {

0 commit comments

Comments
 (0)