Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix GH-10026: Garbage collection stops after exception in SoapClient #10283

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

Open
nielsdos wants to merge 3 commits into php:PHP-8.1
base: PHP-8.1
Choose a base branch
Loading
from nielsdos:fix-10026

Conversation

Copy link
Member

@nielsdos nielsdos commented Jan 10, 2023

Closes GH-10026

In some places where zend_bailout() is used, PHP recovers and normal execution of the script can continue. This is problematic because zend_bailout() protects the GC; causing garbage not to be collected in the future. This PR introduces a new variant of zend_bailout(): zend_bailout_without_gc_protect(). We can use it in places where we know we can recover and GC must still be enabled.

abienvenu, iluuu1994, and arnaud-lb reacted with thumbs up emoji
nielsdos and others added 3 commits January 10, 2023 22:13
This allows users to bail out of a try-catch without protecting the GC
in case the error is recoverable and normal execution will continue.
Co-authored-by: abienvenu <abi@abienvenu.net>
@nielsdos nielsdos changed the title (削除) Fix GH-10026 (削除ここまで) (追記) Fix GH-10026: Garbage collection stops after exception in SoapClient (追記ここまで) Jan 10, 2023
Copy link
Member

@iluuu1994 iluuu1994 left a comment

Choose a reason for hiding this comment

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

This sounds sensible to me. TBH I don't know why the gc_protect() is necessary. I'm not sure if it's just there to improve performance on fatal shutdowns or to protect from some kind of memory corruption, tests pass without it.

@dstogov Does this look ok to you?

@@ -1175,20 +1175,24 @@ ZEND_COLD void zenderror(const char *error) /* {{{ */
}
/* }}} */

ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno) /* {{{ */
ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout_without_gc_protect(const char *filename, uint32_t lineno)
Copy link
Member

@iluuu1994 iluuu1994 Feb 17, 2023

Choose a reason for hiding this comment

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

Maybe we could pick a more generic name, like _zend_nonfatal_bailout to make it more clear which is to be used.

arnaud-lb reacted with thumbs up emoji
Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

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

I don't have a strong opinion about this PR yet.

Another possible approach is to remember and restore the original value of gc_protected() in the "safe" catch places.

Note that zend_bailuot() also sets CG(unclean_shutdown) that may prevent automatic GC and "safe" destruction of global symbol table. We may also keep it in "safe" places.

BTW I can't be sure when zend_bailout() and zend_catch are safe. It's possible to prove safety only if we know both source and destination of longjmp().

I don't like zend_bailout_without_gc_protect() name. I would prefer zend_safe/clean_bailout or zend_bailout_safe/clean.

iluuu1994 and arnaud-lb reacted with thumbs up emoji
Copy link
Member

@dstogov Can you explain why gc_protect(1); is there in the first place? Is it to avoid unnecessary additions to the GC buffer that will never be cleaned up? We can document this in a comment. This will make it easier to understand whether using the new method that doesn't protect the GC is safe to use.

Copy link
Member

dstogov commented Feb 20, 2023

Note that gc_bailout() wasn't designed to be caught and continue normal execution

  • CG(unclean_shutdown) - disabled GC run at shut-down
  • gc_protect() - disabled future GC root collection

Copy link
Member

Note that [zend]_bailout() wasn't designed to be caught and continue normal execution

We could try to stop doing this in master.

From my understanding, SOAP leverages zend_catch to convert fatal errors into exceptions. We could do it the other way around.

Unfortunately, SOAP does that for all errors, not only SOAP ones, and it will not be possible to stop using zend_catch for these. Maybe we should stop catching these, as this will result in crashes or memory leaks. Also, fatal errors are less frequent now that many have been replaced by exceptions.

Copy link
Member

dstogov commented Apr 3, 2023

Note that [zend]_bailout() wasn't designed to be caught and continue normal execution

We could try to stop doing this in master.

From my understanding, SOAP leverages zend_catch to convert fatal errors into exceptions. We could do it the other way around.

It would be great to have the other way. I didn't have a better idea.

Unfortunately, SOAP does that for all errors, not only SOAP ones

This is done on purpose. SOAP server talks to SOAP clients and in case of PHP fatal errors, it should respond in a way that might be understand by clients.

, and it will not be possible to stop using zend_catch for these. Maybe we should stop catching these, as this will result in crashes or memory leaks. Also, fatal errors are less frequent now that many have been replaced by exceptions.

Fatal errors in SOAP client may be replaced by exceptions, but this will require manual error recovery along the C call stack (releasing all the allocated data).

arnaud-lb reacted with thumbs up emoji

Copy link
Member

This is done on purpose. SOAP server talks to SOAP clients and in case of PHP fatal errors, it should respond in a way that might be understand by clients.

I see, this didn't occur to me. This appears to be done in a safe way in SOAPServer, though, as this always bailouts in the end. soap_error_handler responds to the client, and then bailouts.

Fatal errors in SOAP client may be replaced by exceptions, but this will require manual error recovery along the C call stack (releasing all the allocated data).

👍

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

@iluuu1994 iluuu1994 iluuu1994 left review comments

@dstogov dstogov dstogov left review comments

@arnaud-lb arnaud-lb Awaiting requested review from arnaud-lb

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /