From 81f394906cc8b3dd10a5762109f71724e9563050 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Wed, 25 Mar 2026 12:21:12 -0400 Subject: [PATCH] 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-19983 --- Zend/tests/fibers/gh19983.phpt | 29 +++++++++++++++++++++++++++++ Zend/zend_gc.c | 4 +++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/fibers/gh19983.phpt diff --git a/Zend/tests/fibers/gh19983.phpt b/Zend/tests/fibers/gh19983.phpt new file mode 100644 index 000000000000..156edc391815 --- /dev/null +++ b/Zend/tests/fibers/gh19983.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-19983 (GC Assertion Failure with fibers, generators and destructors) +--SKIPIF-- + +--INI-- +memory_limit=128M +--FILE-- +current(); + }); + $fiber->start(); + } +} +new a; +?> +--EXPECTF-- +Fatal error: Allowed memory size of %d bytes exhausted%s diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 7b2ff49a7363..ffd427eac5bc 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -1893,13 +1893,15 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end) GC_G(dtor_idx) = GC_FIRST_ROOT; GC_G(dtor_end) = GC_G(first_unused); + zend_object *exception = NULL; + remember_prev_exception(&exception); + if (UNEXPECTED(!fiber)) { fiber = gc_create_destructor_fiber(); } else { zend_fiber_resume(fiber, NULL, NULL); } - zend_object *exception = NULL; remember_prev_exception(&exception); for (;;) {