Merge branch 'PHP-8.3' into PHP-8.4

* PHP-8.3:
  [ci skip] NEWS for GH-16025
  [ci skip] NEWS for GH-16025
  Fix assertion failure in generator dtor (#16025)
This commit is contained in:
Arnaud Le Blanc 2024-10-02 12:33:06 +02:00
commit bc317d3afc
No known key found for this signature in database
GPG Key ID: 0098C05DD15ABC13
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

@ -212,43 +212,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

@ -101,7 +101,6 @@ static const uint8_t ZEND_GENERATOR_FORCED_CLOSE = 0x2;
static const uint8_t ZEND_GENERATOR_AT_FIRST_YIELD = 0x4;
static const uint8_t ZEND_GENERATOR_DO_INIT = 0x8;
static const uint8_t ZEND_GENERATOR_IN_FIBER = 0x10;
static const uint8_t ZEND_GENERATOR_DTOR_VISITED = 0x20;
void zend_register_generator_ce(void);
ZEND_API void zend_generator_close(zend_generator *generator, bool finished_execution);