From 628e6abde2fdc446be61152647e42c294e949dfd Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 24 Sep 2024 15:45:49 +0200 Subject: [PATCH] Fix assertion failure in generator dtor --- Zend/tests/gh15866.phpt | 53 +++++++++++++++++++++++++++++++++++++++++ Zend/zend_generators.c | 25 +++++-------------- Zend/zend_generators.h | 1 - 3 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 Zend/tests/gh15866.phpt diff --git a/Zend/tests/gh15866.phpt b/Zend/tests/gh15866.phpt new file mode 100644 index 0000000000000..99a3a6e6a9524 --- /dev/null +++ b/Zend/tests/gh15866.phpt @@ -0,0 +1,53 @@ +--TEST-- +GH-15866: Core dumped in Zend/zend_generators.c +--FILE-- +next(); + } finally { + print "Fiber finally\n"; + } +}); +$canary->value = $fiber; +$fiber->start(); + +// Reset roots +gc_collect_cycles(); + +// Add to roots, create garbage cycles +$fiber = $iterable = $canary = null; + +print "Collect cycles\n"; +gc_collect_cycles(); + +?> +==DONE== +--EXPECT-- +Collect cycles +Canary::__destruct +Generator finally +Fiber finally +==DONE== diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 4ac45949bd34a..9089d821f3016 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -218,43 +218,30 @@ static zend_always_inline void clear_link_to_root(zend_generator *generator) { } } -/* In the context of zend_generator_dtor_storage during shutdown, check if - * the intermediate node 'generator' is running in a fiber */ +/* Check if the node 'generator' is running in a fiber */ static inline bool check_node_running_in_fiber(zend_generator *generator) { - ZEND_ASSERT(EG(flags) & EG_FLAGS_IN_SHUTDOWN); ZEND_ASSERT(generator->execute_data); - if (generator->flags & ZEND_GENERATOR_IN_FIBER) { + if (EXPECTED(generator->flags & ZEND_GENERATOR_IN_FIBER)) { return true; } - if (generator->node.children == 0) { + if (EXPECTED(generator->node.children == 0)) { return false; } - if (generator->flags & ZEND_GENERATOR_DTOR_VISITED) { - return false; - } - generator->flags |= ZEND_GENERATOR_DTOR_VISITED; - if (generator->node.children == 1) { - if (check_node_running_in_fiber(generator->node.child.single)) { - goto in_fiber; - } - return false; + return check_node_running_in_fiber(generator->node.child.single); } zend_generator *child; ZEND_HASH_FOREACH_PTR(generator->node.child.ht, child) { if (check_node_running_in_fiber(child)) { - goto in_fiber; + return true; } } ZEND_HASH_FOREACH_END(); - return false; -in_fiber: - generator->flags |= ZEND_GENERATOR_IN_FIBER; - return true; + return false; } static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index a41fb7699d842..00d38a9d28d3f 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -93,7 +93,6 @@ static const zend_uchar ZEND_GENERATOR_FORCED_CLOSE = 0x2; static const zend_uchar ZEND_GENERATOR_AT_FIRST_YIELD = 0x4; static const zend_uchar ZEND_GENERATOR_DO_INIT = 0x8; static const zend_uchar ZEND_GENERATOR_IN_FIBER = 0x10; -static const zend_uchar ZEND_GENERATOR_DTOR_VISITED = 0x20; void zend_register_generator_ce(void); ZEND_API void zend_generator_close(zend_generator *generator, bool finished_execution);