Skip to content

Fix destruction of suspended generators in suspended fibers during shutdown #15158

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

Merged
merged 2 commits into from
Jul 30, 2024

Conversation

arnaud-lb
Copy link
Member

Fixes #15108.

In #10462 we ensured that generators running in a fiber are not destroyed before the fiber:

The shutdown sequence calls the destructor of any live generator or fiber (or any object).

When a fiber is suspended in a generator, the fiber destructor will resume the execution the generator, which may be already be destroyed. This leads to the issues described in # 9916.

Because of this, we must not attempt to destroy a generator that was executing in a suspended fiber.

The fiber destructor conveniently throws a zend_ce_graceful_exit in the fiber context, which will also properly terminate the generator (and execute its finally blocks). I believe that this has the same semantics as the generator destructor.

This was extended to support yield from in 00be6e1 and b9bca2d (I can not find the related PR anymore).

Here I fix two additional cases not handled by #10462:

  • The ZEND_GENERATOR_IN_FIBER flag was not added when resuming a yield from $nonGenerator. I fix that by adding the flag earlier.

  • When a generator that is running in a fiber has multiple children (aka multiple generators yielding from it), all of them could be considered to also run in a fiber (only one actually is), and could leak if not destroyed before shutdown.

Unfortunately the second one requires traversing the child tree (at most once) during dtor if the root is marked ZEND_GENERATOR_IN_FIBER.

@arnaud-lb arnaud-lb changed the base branch from master to PHP-8.2 July 29, 2024 16:44
@arnaud-lb arnaud-lb force-pushed the gh15108 branch 2 times, most recently from 2119053 to c4fd31a Compare July 29, 2024 17:04
@arnaud-lb arnaud-lb marked this pull request as ready for review July 30, 2024 10:40
@arnaud-lb arnaud-lb requested a review from bwoebi July 30, 2024 10:41
@@ -722,6 +774,13 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
return;
}

if (EG(active_fiber)) {
orig_generator->flags |= ZEND_GENERATOR_IN_FIBER;
if (generator != orig_generator) {
Copy link
Member

Choose a reason for hiding this comment

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

Redundant condition (a few lines deeper as well).

…utdown

The generator destructor is a no-op when the generator is running in a fiber,
because unwinding the fiber will resume the generator. Normally the destructor
is never called in this case, but this can happen during shutdown.

We detect that a generator is running in a fiber with the
ZEND_GENERATOR_IN_FIBER flag.

This change fixes two cases in which this mechanism was broken:

 - The flag was not added when resuming a 'yield from $nonGenerator', as this is
   handled in a separate code path
 - When a generator that is running in a fiber has multiple children (aka
   multiple generators yielding from it), all of them could be considered to
   also run in a fiber (only one actually is), and could leak if not destroyed
   before shutdown.
Copy link
Member

@bwoebi bwoebi left a comment

Choose a reason for hiding this comment

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

It looks right to me, visiting all generators only once sounds good to me.

Maybe call ZEND_GENERATOR_VISITED ZEND_GENERATOR_DTOR_VISITED instead.

@arnaud-lb arnaud-lb merged commit 99e0d3f into php:PHP-8.2 Jul 30, 2024
7 of 9 checks passed
arnaud-lb added a commit that referenced this pull request Jul 30, 2024
* PHP-8.2:
  [ci skip] NEWS
  Fix destruction of generator running in fibers during shutdown (#15158)
arnaud-lb added a commit that referenced this pull request Jul 30, 2024
* PHP-8.3:
  [ci skip] NEWS
  [ci skip] NEWS
  Fix destruction of generator running in fibers during shutdown (#15158)
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.

Segfault / Assertion failed: (p->refcount > 0), function zend_gc_delref, file zend_types.h, line 1342
2 participants