mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Normally we prevent generators from being resumed while they are already running, but we failed to do so for generators delegating to non-Generators. As a result such generator can be resumed, terminated, which causes unexpected results (crashes) later. In gh19306.phpt in particular, the generator delegate It::getIterator() suspends while being called by generator g(). We then resume g(), which throws while trying to resume It::getIterator(). This causes g() and It::getIterator() to be released. We then UAF when resuming the Fiber in It::getIterator(). Fix this by ensuring that generators are marked as running while they fetch the next value from the delegate. Fixes GH-19306 Closes GH-19315
41 lines
691 B
PHP
41 lines
691 B
PHP
--TEST--
|
|
GH-19306: Generator suspended in yield from may be resumed
|
|
--FILE--
|
|
<?php
|
|
|
|
class It implements IteratorAggregate
|
|
{
|
|
public function getIterator(): Generator
|
|
{
|
|
yield "";
|
|
Fiber::suspend();
|
|
}
|
|
}
|
|
function g()
|
|
{
|
|
yield from new It();
|
|
}
|
|
$a = g();
|
|
$fiber = new Fiber(function () use ($a) {
|
|
echo "Fiber start\n";
|
|
$a->next();
|
|
echo "Fiber return\n";
|
|
});
|
|
$fiber->start();
|
|
echo "Fiber suspended\n";
|
|
try {
|
|
$a->next();
|
|
} catch (Throwable $t) {
|
|
echo $t->getMessage(), "\n";
|
|
}
|
|
echo "Destroying fiber\n";
|
|
$fiber = null;
|
|
echo "Shutdown\n";
|
|
?>
|
|
--EXPECT--
|
|
Fiber start
|
|
Fiber suspended
|
|
Cannot resume an already running generator
|
|
Destroying fiber
|
|
Shutdown
|