Skip to content

Fix GH-24264: Unwind/GracefulExit discarded in spl_iterators.c - #24268

Closed
lazerg wants to merge 4 commits into
php:PHP-8.4from
lazerg:fix/gh-24264
Closed

lazerg wants to merge 4 commits into
php:PHP-8.4from
lazerg:fix/gh-24264

Conversation

@lazerg

@lazerg lazerg commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

With CATCH_GET_CHILD, RecursiveIteratorIterator and RecursiveCachingIterator call zend_clear_exception() on any exception thrown by hasChildren(), getChildren(), beginChildren() and friends. That also swallows the unwind exit from exit() and the graceful exit used when destroying fibers, so the script keeps running. These exceptions are now passed through as if CATCH_GET_CHILD was not set.

Fixes #24264

@Girgias Girgias left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we should even be using zend_clear_exception.

@lazerg

lazerg commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

What would you use instead? CATCH_GET_CHILD is meant to ignore exceptions from getChildren()/hasChildren(), so the exception has to be dropped somewhere. Do you want it to catch only Exception and let Error through, or something else?

@ndossche

Copy link
Copy Markdown
Member

The C code is supposed to do the equivalent of a PHP try-catch that throws away the exception. That matches the semantics description of CATCH_GET_CHILD.
We should only be doing a zend_clear_exception in case it's not one of the uncatchable exceptions, so in that sense the PR is correct.
Please expand the tests a bit, e.g. at least the getChildren() case.

@lazerg

lazerg commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

I added getChildren() tests for RecursiveIteratorIterator and RecursiveCachingIterator in cc75dea. I also added one where a fiber is destroyed while it is suspended in getChildren(), so the graceful exit path has a test too.

@ndossche

Copy link
Copy Markdown
Member

Can you please drop the NEWS change? This is something we always do ourselves when upmerging anyway, and it is blocking CI runs on this PR due to the merge conflict

@lazerg

lazerg commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Done, I removed the NEWS entry in a2e52dd.

@Girgias Girgias left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPL is truly the gift that keeps on giving.

Comment thread ext/spl/spl_iterators.c Outdated
}
}

static bool spl_can_catch_exception(void)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you pass the flags as a parameter so the !(object->flags & RIT_CATCH_GET_CHILD) logic can be moved into this function.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ed3c6f0. The function now takes the flags and checks CATCH_GET_CHILD itself, so both iterators use it the same way.

@ndossche ndossche left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this version is slightly worse than the version with flags separate because now it depends on this implementation detail:

#define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD

However, this will work, and I can't be bothered to fight over this. Probably other code already depends on this anyway

@ndossche ndossche closed this in 861d2b6 Oct 25, 2026
@ndossche

Copy link
Copy Markdown
Member

Merged, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants