Skip to content

Commit aeca4d2

Browse files
arnaud-lbmarcosmarcolin
authored andcommitted
Prevent dtor of generator in suspended fiber (#10462)
Generators that suspended a fiber should not be dtor because they will be executed during the fiber dtor. Fiber dtor throws an exception in the fiber's context in order to unwind and execute finally blocks, which will also properly dtor the generator. Fixes GH-9916
1 parent 4901fd6 commit aeca4d2

13 files changed

+398
-1
lines changed

Diff for: Zend/tests/gh9916-001.phpt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug GH-9916 001 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
try {
8+
print "Before suspend\n";
9+
Fiber::suspend();
10+
print "Not executed";
11+
yield;
12+
} finally {
13+
print "Finally\n";
14+
}
15+
print "Not executed";
16+
})();
17+
$fiber = new Fiber(function() use ($gen, &$fiber) {
18+
$gen->current();
19+
print "Not executed";
20+
});
21+
$fiber->start();
22+
?>
23+
==DONE==
24+
--EXPECT--
25+
Before suspend
26+
==DONE==
27+
Finally

Diff for: Zend/tests/gh9916-002.phpt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Bug GH-9916 002 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
print "Before suspend\n";
8+
Fiber::suspend();
9+
print "Not executed\n";
10+
yield;
11+
})();
12+
$fiber = new Fiber(function() use ($gen, &$fiber) {
13+
$gen->current();
14+
print "Not executed";
15+
});
16+
$fiber->start();
17+
?>
18+
==DONE==
19+
--EXPECT--
20+
Before suspend
21+
==DONE==

Diff for: Zend/tests/gh9916-003.phpt

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Bug GH-9916 003 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
try {
8+
yield from (function () {
9+
$x = new stdClass;
10+
try {
11+
print "Before suspend\n";
12+
Fiber::suspend();
13+
print "Not executed\n";
14+
yield;
15+
} finally {
16+
print "Finally (inner)\n";
17+
}
18+
})();
19+
print "Not executed\n";
20+
yield;
21+
} finally {
22+
print "Finally\n";
23+
}
24+
})();
25+
$fiber = new Fiber(function() use ($gen, &$fiber) {
26+
$gen->current();
27+
print "Not executed";
28+
});
29+
$fiber->start();
30+
?>
31+
==DONE==
32+
--EXPECT--
33+
Before suspend
34+
==DONE==
35+
Finally (inner)
36+
Finally

Diff for: Zend/tests/gh9916-004.phpt

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Bug GH-9916 004 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
yield from (function () {
8+
$x = new stdClass;
9+
print "Before suspend\n";
10+
Fiber::suspend();
11+
print "Not executed\n";
12+
yield;
13+
})();
14+
print "Not executed\n";
15+
yield;
16+
})();
17+
$fiber = new Fiber(function() use ($gen, &$fiber) {
18+
$gen->current();
19+
print "Not executed";
20+
});
21+
$fiber->start();
22+
?>
23+
==DONE==
24+
--EXPECT--
25+
Before suspend
26+
==DONE==

Diff for: Zend/tests/gh9916-005.phpt

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Bug GH-9916 005 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
$fiber = yield;
8+
print "Before suspend\n";
9+
Fiber::suspend();
10+
yield;
11+
})();
12+
$fiber = new Fiber(function() use ($gen, &$fiber) {
13+
$gen->send($fiber);
14+
$gen->current();
15+
});
16+
$fiber->start();
17+
18+
$gen = null;
19+
$fiber = null;
20+
gc_collect_cycles();
21+
?>
22+
==DONE==
23+
--EXPECT--
24+
Before suspend
25+
==DONE==

Diff for: Zend/tests/gh9916-006.phpt

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
Bug GH-9916 006 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
yield from (function () {
8+
$x = new stdClass;
9+
print "Before suspend\n";
10+
Fiber::suspend();
11+
print "After suspend\n";
12+
yield;
13+
})();
14+
yield from (function () {
15+
$x = new stdClass;
16+
print "Before exit\n";
17+
exit;
18+
print "Not executed\n";
19+
yield;
20+
})();
21+
yield;
22+
})();
23+
$fiber = new Fiber(function() use ($gen, &$fiber) {
24+
$gen->current();
25+
print "Fiber return\n";
26+
});
27+
$fiber->start();
28+
$fiber->resume();
29+
$gen->next();
30+
$gen->current();
31+
?>
32+
==DONE==
33+
--EXPECT--
34+
Before suspend
35+
After suspend
36+
Fiber return
37+
Before exit

Diff for: Zend/tests/gh9916-007.phpt

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
Bug GH-9916 007 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$it = new class implements Iterator
6+
{
7+
public function current(): mixed
8+
{
9+
return null;
10+
}
11+
12+
public function key(): mixed
13+
{
14+
return 0;
15+
}
16+
17+
public function next(): void
18+
{
19+
}
20+
21+
public function rewind(): void
22+
{
23+
try {
24+
print "Before suspend\n";
25+
Fiber::suspend();
26+
print "Not executed\n";
27+
} finally {
28+
print "Finally (iterator)\n";
29+
}
30+
}
31+
32+
public function valid(): bool
33+
{
34+
return true;
35+
}
36+
};
37+
38+
$gen = (function() use ($it) {
39+
try {
40+
yield from $it;
41+
print "Not executed\n";
42+
} finally {
43+
print "Finally\n";
44+
}
45+
})();
46+
$fiber = new Fiber(function() use ($gen, &$fiber) {
47+
$gen->current();
48+
print "Not executed";
49+
});
50+
$fiber->start();
51+
?>
52+
==DONE==
53+
--EXPECT--
54+
Before suspend
55+
==DONE==
56+
Finally (iterator)
57+
Finally

Diff for: Zend/tests/gh9916-008.phpt

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Bug GH-9916 008 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$it = new class implements Iterator
6+
{
7+
public function current(): mixed
8+
{
9+
return null;
10+
}
11+
12+
public function key(): mixed
13+
{
14+
return 0;
15+
}
16+
17+
public function next(): void
18+
{
19+
}
20+
21+
public function rewind(): void
22+
{
23+
$x = new stdClass;
24+
print "Before suspend\n";
25+
Fiber::suspend();
26+
}
27+
28+
public function valid(): bool
29+
{
30+
return true;
31+
}
32+
};
33+
34+
$gen = (function() use ($it) {
35+
$x = new stdClass;
36+
yield from $it;
37+
})();
38+
$fiber = new Fiber(function() use ($gen, &$fiber) {
39+
$gen->current();
40+
print "Not executed";
41+
});
42+
$fiber->start();
43+
?>
44+
==DONE==
45+
--EXPECT--
46+
Before suspend
47+
==DONE==

Diff for: Zend/tests/gh9916-009.phpt

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Bug GH-9916 009 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
try {
8+
print "Before suspend\n";
9+
Fiber::suspend();
10+
print "Not executed\n";
11+
} finally {
12+
print "Finally\n";
13+
yield from ['foo' => new stdClass];
14+
print "Not executed\n";
15+
}
16+
})();
17+
$fiber = new Fiber(function() use ($gen, &$fiber) {
18+
$gen->current();
19+
print "Not executed\n";
20+
});
21+
$fiber->start();
22+
?>
23+
==DONE==
24+
--EXPECTF--
25+
Before suspend
26+
==DONE==
27+
Finally
28+
29+
Fatal error: Uncaught Error: Cannot use "yield from" in a force-closed generator in %s:%d
30+
Stack trace:
31+
#0 [internal function]: {closure}()
32+
#1 %s(%d): Generator->current()
33+
#2 [internal function]: {closure}()
34+
#3 {main}
35+
thrown in %s on line %d

Diff for: Zend/tests/gh9916-010.phpt

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
Bug GH-9916 010 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
print "Before yield\n";
8+
yield from (function () {
9+
$x = new stdClass;
10+
print "Before yield 2\n";
11+
yield;
12+
print "Before suspend\n";
13+
Fiber::suspend();
14+
})();
15+
})();
16+
17+
$fiber = new Fiber(function () use ($gen, &$fiber) {
18+
print "Before current\n";
19+
$gen->current();
20+
print "Before next\n";
21+
$gen->next();
22+
print "Not executed\n";
23+
});
24+
25+
$fiber->start();
26+
?>
27+
==DONE==
28+
--EXPECT--
29+
Before current
30+
Before yield
31+
Before yield 2
32+
Before next
33+
Before suspend
34+
==DONE==

Diff for: Zend/tests/gh9916-011.phpt

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
Bug GH-9916 011 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes)
3+
--FILE--
4+
<?php
5+
$gen = (function() {
6+
$x = new stdClass;
7+
print "Before yield\n";
8+
$from = (function () {
9+
$x = new stdClass;
10+
print "Before yield 2\n";
11+
yield;
12+
print "Before suspend\n";
13+
Fiber::suspend();
14+
print "Not executed\n";
15+
yield;
16+
})();
17+
try {
18+
yield from $from;
19+
} finally {
20+
$from->next();
21+
}
22+
})();
23+
24+
$fiber = new Fiber(function () use ($gen, &$fiber) {
25+
print "Before current\n";
26+
$gen->current();
27+
print "Before next\n";
28+
$gen->next();
29+
print "Not executed\n";
30+
});
31+
32+
$fiber->start();
33+
?>
34+
==DONE==
35+
--EXPECT--
36+
Before current
37+
Before yield
38+
Before yield 2
39+
Before next
40+
Before suspend
41+
==DONE==

0 commit comments

Comments
 (0)