Skip to content

Commit 5d6bcfa

Browse files
committed
Zend: zend_fiber_execute() discards exit() in a destroyed fiber.
Fix #24265 A destroyed fiber swallowed UnwindExit along with the GracefulExit used to unwind it, so exit() in a finally block or destructor was lost. Only the GracefulExit is swallowed now.
1 parent d1fdbba commit 5d6bcfa

3 files changed

Lines changed: 60 additions & 4 deletions

File tree

‎Zend/tests/fibers/gh24265-001.phpt‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-24265 (exit() in a finally block of a destroyed fiber is discarded)
3+
--CREDITS--
4+
iluuu1994
5+
--FILE--
6+
<?php
7+
8+
$fiber = new Fiber(function () {
9+
try {
10+
Fiber::suspend();
11+
} finally {
12+
exit(1);
13+
}
14+
});
15+
16+
$fiber->start();
17+
echo "Before destroy", PHP_EOL;
18+
unset($fiber);
19+
20+
echo "Not reached", PHP_EOL;
21+
22+
?>
23+
--EXPECT--
24+
Before destroy

‎Zend/tests/fibers/gh24265-002.phpt‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-24265 (exit() in a destroyed fiber is discarded while an exception is pending)
3+
--FILE--
4+
<?php
5+
6+
function test() {
7+
$fiber = new Fiber(function () {
8+
try {
9+
Fiber::suspend();
10+
} finally {
11+
exit(1);
12+
}
13+
});
14+
15+
$fiber->start();
16+
echo "Before destroy", PHP_EOL;
17+
throw new Exception("pending");
18+
}
19+
20+
try {
21+
test();
22+
} catch (Exception $e) {
23+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
24+
}
25+
26+
echo "Not reached", PHP_EOL;
27+
28+
?>
29+
--EXPECT--
30+
Before destroy

‎Zend/zend_fibers.c‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,7 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer)
613613
ZVAL_UNDEF(&fiber->fci.function_name);
614614

615615
if (EG(exception)) {
616-
if (!(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)
617-
|| !(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)))
618-
) {
616+
if (!(fiber->flags & ZEND_FIBER_FLAG_DESTROYED) || !zend_is_graceful_exit(EG(exception))) {
619617
fiber->flags |= ZEND_FIBER_FLAG_THREW;
620618
transfer->flags = ZEND_FIBER_TRANSFER_FLAG_ERROR;
621619

@@ -797,7 +795,11 @@ static void zend_fiber_object_destroy(zend_object *object)
797795
zend_rethrow_exception(EG(current_execute_data));
798796
}
799797

800-
zend_exception_set_previous(EG(exception), exception);
798+
if (exception && zend_is_unwind_exit(EG(exception))) {
799+
OBJ_RELEASE(exception);
800+
} else {
801+
zend_exception_set_previous(EG(exception), exception);
802+
}
801803

802804
if (!EG(current_execute_data)) {
803805
zend_exception_error(EG(exception), E_ERROR);

0 commit comments

Comments
 (0)