Skip to content

Commit dd4a080

Browse files
committed
Simplify and fix generator tree management
This makes a number of related changes to the generator tree management, that should hopefully make it easier to understand, more robust and faster for the common linear-chain case. Fixes https://bugs.php.net/bug.php?id=80240, which was the original motivation here. * Generators now only add a ref to their direct parent. * Nodes only store their children, not their leafs, which avoids any need for leaf updating. This means it's no longer possible to fetch the child for a certain leaf, which is something we only needed in one place (update_current). If multi-children nodes are involved, this will require doing a walk in the other direction (from leaf to root). It does not affect the common case of single-child nodes. * The root/leaf pointers are now seen as a pair. One leaf generator can point to the current root. If a different leaf generator is used, we'll move the root pointer over to that one. Again, this is a cache to make the common linear chain case fast, trees may need to scan up the parent link. Closes GH-6344.
1 parent ac87880 commit dd4a080

File tree

5 files changed

+221
-258
lines changed

5 files changed

+221
-258
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Generator backtrace with multi yield from
3+
--FILE--
4+
<?php
5+
6+
function gen() {
7+
yield 1;
8+
debug_print_backtrace();
9+
yield 2;
10+
}
11+
12+
function from($gen) {
13+
yield from $gen;
14+
}
15+
16+
$gen1 = gen();
17+
$gen2 = from($gen1);
18+
$gen3 = from($gen2);
19+
var_dump($gen3->current());
20+
$gen2->next();
21+
var_dump($gen2->current());
22+
$gen2->next();
23+
var_dump($gen2->current());
24+
25+
?>
26+
--EXPECTF--
27+
int(1)
28+
int(1)
29+
#0 gen() called at [%s:10]
30+
#1 from(Generator Object ())
31+
#2 Generator->next() called at [%s:19]
32+
int(2)

Zend/tests/generators/bug80240.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Bug #80240: Use after free multi yield from
3+
--FILE--
4+
<?php
5+
6+
function gen() {
7+
yield 0;
8+
yield from gen();
9+
}
10+
11+
function bar($gen) {
12+
yield from $gen;
13+
}
14+
15+
$gen = gen();
16+
$a = bar($gen);
17+
$b = bar($gen);
18+
$a->rewind();
19+
$b->rewind();
20+
$a->next();
21+
unset($gen);
22+
unset($a);
23+
unset($b);
24+
25+
?>
26+
===DONE===
27+
--EXPECT--
28+
===DONE===
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Leaf link may need to be invalidated depending on dtor order
3+
--FILE--
4+
<?php
5+
6+
function gen2() {
7+
yield 1;
8+
}
9+
function gen() {
10+
yield from gen2();
11+
}
12+
function bar($g) {
13+
yield from $g;
14+
}
15+
16+
$gen = gen();
17+
$bar = bar($gen);
18+
var_dump($bar->current());
19+
$copy = $bar;
20+
unset($gen);
21+
22+
?>
23+
--EXPECT--
24+
int(1)

0 commit comments

Comments
 (0)