Skip to content

Commit 4166653

Browse files
committed
Fix exception thrown during fiber destruction
Previously an exception thrown during fiber destruction resulted in a fatal error, but that exception should be able to be caught (unless we’ve entered shutdown, then still use a fatal error so the error is not hidden).
1 parent 79d237c commit 4166653

5 files changed

+48
-13
lines changed

Zend/tests/fibers/suspend-in-force-close-fiber-after-shutdown.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Suspend in force closed fiber after shutdown
2+
Suspend in force-closed fiber after shutdown
33
--FILE--
44
<?php
55

@@ -19,7 +19,7 @@ echo "done\n";
1919
--EXPECTF--
2020
done
2121

22-
Fatal error: Uncaught FiberError: Cannot suspend in a force closed fiber in %ssuspend-in-force-close-fiber-after-shutdown.php:%d
22+
Fatal error: Uncaught FiberError: Cannot suspend in a force-closed fiber in %ssuspend-in-force-close-fiber-after-shutdown.php:%d
2323
Stack trace:
2424
#0 %ssuspend-in-force-close-fiber-after-shutdown.php(%d): Fiber::suspend()
2525
#1 [internal function]: {closure}()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Suspend in force-closed fiber, catching exception thrown from destructor
3+
--FILE--
4+
<?php
5+
6+
try {
7+
(function (): void {
8+
$fiber = new Fiber(function (): void {
9+
try {
10+
Fiber::suspend();
11+
} finally {
12+
Fiber::suspend();
13+
}
14+
});
15+
16+
$fiber->start();
17+
})();
18+
} catch (FiberError $exception) {
19+
echo $exception->getMessage(), "\n";
20+
}
21+
22+
echo "done\n";
23+
24+
?>
25+
--EXPECTF--
26+
Cannot suspend in a force-closed fiber
27+
done

Zend/tests/fibers/suspend-in-force-close-fiber.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Suspend in force closed fiber
2+
Suspend in force-closed fiber
33
--FILE--
44
<?php
55

@@ -17,7 +17,7 @@ unset($fiber);
1717

1818
?>
1919
--EXPECTF--
20-
Fatal error: Uncaught FiberError: Cannot suspend in a force closed fiber in %ssuspend-in-force-close-fiber.php:%d
20+
Fatal error: Uncaught FiberError: Cannot suspend in a force-closed fiber in %ssuspend-in-force-close-fiber.php:%d
2121
Stack trace:
2222
#0 %ssuspend-in-force-close-fiber.php(%d): Fiber::suspend()
2323
#1 [internal function]: {closure}()

Zend/tests/fibers/unfinished-fiber-with-throw-in-finally.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ fiber
4444
inner finally
4545
finally exception
4646
outer finally
47-
Cannot suspend in a force closed fiber
47+
Cannot suspend in a force-closed fiber
4848
done

Zend/zend_fibers.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,6 @@ static void ZEND_STACK_ALIGNED zend_fiber_execute(zend_fiber_context *context)
349349
if (fiber->status == ZEND_FIBER_STATUS_SHUTDOWN) {
350350
if (EXPECTED(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)))) {
351351
zend_clear_exception();
352-
} else {
353-
zend_exception_error(EG(exception), E_ERROR);
354352
}
355353
} else {
356354
fiber->status = ZEND_FIBER_STATUS_THREW;
@@ -380,14 +378,24 @@ static void zend_fiber_object_destroy(zend_object *object)
380378
{
381379
zend_fiber *fiber = (zend_fiber *) object;
382380

383-
if (fiber->status == ZEND_FIBER_STATUS_SUSPENDED) {
384-
zend_object *exception = EG(exception);
385-
EG(exception) = NULL;
381+
if (fiber->status != ZEND_FIBER_STATUS_SUSPENDED) {
382+
return;
383+
}
384+
385+
zend_object *exception = EG(exception);
386+
EG(exception) = NULL;
387+
388+
fiber->status = ZEND_FIBER_STATUS_SHUTDOWN;
386389

387-
fiber->status = ZEND_FIBER_STATUS_SHUTDOWN;
390+
zend_fiber_switch_to(fiber);
388391

389-
zend_fiber_switch_to(fiber);
392+
if (EG(exception)) {
393+
zend_exception_set_previous(EG(exception), exception);
390394

395+
if (EG(flags) & EG_FLAGS_IN_SHUTDOWN) {
396+
zend_exception_error(EG(exception), E_ERROR);
397+
}
398+
} else {
391399
EG(exception) = exception;
392400
}
393401
}
@@ -471,7 +479,7 @@ ZEND_METHOD(Fiber, suspend)
471479
}
472480

473481
if (UNEXPECTED(fiber->status == ZEND_FIBER_STATUS_SHUTDOWN)) {
474-
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force closed fiber");
482+
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber");
475483
RETURN_THROWS();
476484
}
477485

0 commit comments

Comments
 (0)