Repository navigation
Rethrow exceptions from destructors called by the GC in a fiber - #24118
Merged
Merged
Conversation
When the GC runs destructors in its dedicated fiber, zend_call_function() cannot rethrow their exception into the frame that triggered the GC, since that frame belongs to another fiber. gc_call_destructors_in_fiber() then restores EG(exception) without rethrowing it, so the code following the statement that triggered the GC keeps running until something checks EG(exception), and the exception is dispatched from a stale EG(opline_before_exception), which can skip the enclosing catch block. Rethrow it into the current frame when no exception was pending before the GC run, as zend_fiber_object_destroy() does.
arnaud-lb
added a commit
that referenced
this pull request
Oct 5, 2026
* PHP-8.6: [ci skip] NEWS Rethrow exceptions from destructors called by the GC in a fiber (#24118)
Member
|
Thank you! |
arnaud-lb
added a commit
to nicolas-grekas/php-src
that referenced
this pull request
Oct 5, 2026
* up/PHP-8.4: [ci skip] NEWS Rethrow exceptions from destructors called by the GC in a fiber (php#24118) ext/intl: Use byte offsets in IntlDateFormatter parsing ext/dom: Restore the XPath context after a reentrant evaluation Fix TLS stream EOF detection after close_notify with stale errno (php#24132) Re-generate outdated parse_date.c file ext/standard: Close owned proc_open descriptors on setup failure ext/standard: Keep IPTC headers local to each call ext/standard: Reject incomplete sha1_file reads
t0ny4
pushed a commit
to t0ny4/php-src
that referenced
this pull request
Oct 5, 2026
* PHP-8.4: [ci skip] NEWS Rethrow exceptions from destructors called by the GC in a fiber (php#24118)
t0ny4
pushed a commit
to t0ny4/php-src
that referenced
this pull request
Oct 5, 2026
* PHP-8.5: [ci skip] NEWS Rethrow exceptions from destructors called by the GC in a fiber (php#24118)
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.
Found while working on #24117.
Since 8.4, when the GC is triggered inside a fiber, it calls destructors in a dedicated fiber. If one of them throws, the exception isn't rethrown into the frame that triggered the GC: the code after the triggering statement keeps running, and the exception then escapes the enclosing catch block.
8.3 prints
caught in g(), 8.4 and up printafter assignthenescaped g().zend_call_function()can't rethrow into that frame from the destructor fiber, sogc_call_destructors_in_fiber()now does it when no exception was pending before the GC run, likezend_fiber_object_destroy()does.This conflicts with #24117 on the last lines of
gc_call_destructors_in_fiber(): theEG(opline_before_exception)restore has to come before the rethrow, whichdestructors_013.phptchecks.