1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix assertion failure in generator dtor (#16025)

This commit is contained in:
Arnaud Le Blanc
2024-10-02 12:29:19 +02:00
committed by GitHub
parent 066d18f2e8
commit 6e55f4df23
3 changed files with 59 additions and 20 deletions

53
Zend/tests/gh15866.phpt Normal file
View File

@@ -0,0 +1,53 @@
--TEST--
GH-15866: Core dumped in Zend/zend_generators.c
--FILE--
<?php
class Canary {
public function __construct(public mixed $value) {}
public function __destruct() {
printf("%s\n", __METHOD__);
}
}
function g() {
Fiber::suspend();
}
function f($canary) {
try {
var_dump(yield from g());
} finally {
print "Generator finally\n";
}
}
$canary = new Canary(null);
$iterable = f($canary);
$fiber = new Fiber(function () use ($iterable, $canary) {
try {
$iterable->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==

View File

@@ -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) /* {{{ */

View File

@@ -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);