-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Don't overwrite unwind exception #7459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Would it be feasible to retain the exception in some way so it could be optionally rethrown where the fiber/coroutine is being destroyed? |
We could just force-resume the coroutine which is in IO operation to cancel it instead of killing it by unwind_exit(), then the IO exception will be thrown, user can catch it normally. So I do not think retain the exception when we kill a coroutine with unwind_exit() make sense, and we have also many other ways to interrupt a coroutine like |
Assuming you know the current state of the coroutine, sure, but that may not be the case. External code may not know where a coroutine was suspended, just that it is needs to be destroyed (assuming GC here, correct me if I'm wrong). If another exception is raised during fiber/coroutine destruction, it might be useful to have that information so it can be rethrown/handled/etc. |
Confused part: It seems that we have banned suspending coroutines in GC? I am not totally opposed to keeping exception information, because I just need a way to kill a coroutine silently like send SIGKILL to processes. The intuitive way for me is that after I called exit() the process/thread/coroutine will definetly exit and I always do not care about state of it anymore because I think it's dead/released (or at most some warnings were thrown), of course I know that we cannot guarantee this behaviour in PHP... For me, it would be great if we can guarantee that the exit will always be completed successfully, It's as if I prefer functions with void return type... And, on the one hand, I cannot find a way to construct this situation for the time being (but it may indeed happen), on the other hand, I don’t know how you want to store these exception information? |
Zend/zend_exceptions.c
Outdated
@@ -175,6 +175,12 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* | |||
|
|||
if (exception != NULL) { | |||
zend_object *previous = EG(exception); | |||
if (previous && (zend_is_unwind_exit(previous) || zend_is_graceful_exit(previous))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be limited to unwind_exit only, and leave graceful_exit alone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I may treat unwind_exit() as SIGKILL and graceful_exit() as SIGTERM, it seems reasonable for me in a way... graceful_exit() could be aborted due to other accidents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikic This is limited to internal/extension code, yes? User code would not be able to throw another exception and replace the exception while destroying a fiber?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User code can throw an exception in finally. Though that would work independently of this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems I had a test for the user code behavior. Obviously this didn't affect that and since this only concerns throwing an exception internally, never mind about my question of storing the exception.
@nikic I like your suggestion of only preventing replacement of unwind_exit.
2c57b05
to
e16e8c7
Compare
If it doesn't break anything, is it possible to backport it to all PHP-8.x versions? |
This has been suggested by @twose. When killing a coroutine by throwing an unwind exit into it during an I/O operation, the I/O failure may result in an exception being thrown, which will replace the unwind exit exception and the coroutine will ultimately not exit. This patch avoids this by ignoring the newly thrown exception and keeping the unwind exit exception.