Repository navigation
Fix skipped catch block when switching fibers during exception unwinding - #24117
Merged
Merged
Conversation
zend_fiber_object_destroy() and gc_call_destructors_in_fiber() put the pending exception aside while running another fiber, but not EG(opline_before_exception), which that fiber overwrites. When the frame handling the exception is already at ZEND_HANDLE_EXCEPTION, e.g. because a destructor ran earlier during i_free_compiled_variables(), the later zend_rethrow_exception() does not set it again, and the exception is dispatched from the wrong op, skipping the enclosing try block.
nicolas-grekas
force-pushed
the
fiber-destroy-opline
branch
from
October 6, 2026 14:02
8491e84 to
16fc9db
Compare
* PHP-8.4: (33 commits) Update NEWS ext/mbstring: Fix truncated encoding names resolving to full names (php#23974) Backport PCRE2 security fixes to bundled 10.40 Fix backport ext/pdo: Avoid a duplicate warning for a rejected statement class phpdbg: Fix wrong command names Backport phpGH-24241 to 8.4 [ci skip] Update EXTENSIONS and CODEOWNERS for ext/readline Fix throwing behaviour with recursive arrays in VM Fix phpGH-24229: Use SHUT_WR when closing FastCGI connections (php#24230) Add regression test for phpGH-16821 (php#24228) Fix use-after-free when removing a failing zlib.inflate filter (php#24176) Fix phpGH-24218: Invalid opcode for count() of a literal array without SCCP fix: system ID for Apache graceful restart (php#24184) ext/standard: Validate the bcrypt cost before reading it zend_alloc: move a small block shrunk to the size of the bin below Fix phpGH-23979: Nullsafe operator must not flush delayed oplines of an enclosing function ext/zip: Reject ZipArchive mutators during close() (php#24025) Fix OSS-Fuzz #568005340: FETCH_DIM_FUNC_ARG partial conversion Fix too wide type inference for ASSIGN_DIM_OP ...
arnaud-lb
added a commit
that referenced
this pull request
Oct 12, 2026
* PHP-8.6: Fix skipped catch block when switching fibers during exception unwinding (#24117)
Member
|
Thank you! |
narfbg
pushed a commit
to narfbg/php-src
that referenced
this pull request
Oct 12, 2026
* PHP-8.4: Fix skipped catch block when switching fibers during exception unwinding (php#24117)
narfbg
pushed a commit
to narfbg/php-src
that referenced
this pull request
Oct 12, 2026
* PHP-8.5: Fix skipped catch block when switching fibers during exception unwinding (php#24117)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Destroying a suspended fiber while an exception unwinds can make the engine skip the catch block that should handle that exception:
zend_fiber_object_destroy()puts the pending exception aside while it resumes the fiber, but notEG(opline_before_exception), which the fiber overwrites. BecauseD::__destruct()ran first, the frame ofc()is already atZEND_HANDLE_EXCEPTION, so thezend_rethrow_exception()that followsi_free_compiled_variables()doesn't set it again and the exception is dispatched from the wrong op.gc_call_destructors_in_fiber()has the same issue when the GC runs during unwinding inside a fiber (8.4+).The fix saves and restores the pointer at both places, like
zend_objects_destroy_object()andzend_generator_dtor_storage()already do (see GH-20183 and GH-20714 for the generator side). Saving it inzend_fiber_vm_stateinstead would also work, but backtraces taken in a GC destructor would then report a wrong line for the unwinding frames.Found while investigating a random failure on Symfony's CI, where an exception escaped
Worker::run()when the GC destroyed suspended amphp fibers during unwinding (symfony/symfony#66615).