From 1c34110482322ee2e271bf95a4499aa482427902 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 13 Oct 2026 01:20:01 +0100 Subject: [PATCH 1/2] 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. --- Zend/tests/fibers/gh24265-001.phpt | 24 ++++++++++++++++++++++++ Zend/tests/fibers/gh24265-002.phpt | 30 ++++++++++++++++++++++++++++++ Zend/zend_fibers.c | 10 ++++++---- 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/fibers/gh24265-001.phpt create mode 100644 Zend/tests/fibers/gh24265-002.phpt diff --git a/Zend/tests/fibers/gh24265-001.phpt b/Zend/tests/fibers/gh24265-001.phpt new file mode 100644 index 000000000000..d4eed32fc624 --- /dev/null +++ b/Zend/tests/fibers/gh24265-001.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-24265 (exit() in a finally block of a destroyed fiber is discarded) +--CREDITS-- +iluuu1994 +--FILE-- +start(); +echo "Before destroy", PHP_EOL; +unset($fiber); + +echo "Not reached", PHP_EOL; + +?> +--EXPECT-- +Before destroy diff --git a/Zend/tests/fibers/gh24265-002.phpt b/Zend/tests/fibers/gh24265-002.phpt new file mode 100644 index 000000000000..2a794bc3d02f --- /dev/null +++ b/Zend/tests/fibers/gh24265-002.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-24265 (exit() in a destroyed fiber is discarded while an exception is pending) +--FILE-- +start(); + echo "Before destroy", PHP_EOL; + throw new Exception("pending"); +} + +try { + test(); +} catch (Exception $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "Not reached", PHP_EOL; + +?> +--EXPECT-- +Before destroy diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index 2bebdd8d87f6..b28d0bbb383d 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -645,9 +645,7 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer) zend_fiber_release_callable(fiber); if (EG(exception)) { - if (!(fiber->flags & ZEND_FIBER_FLAG_DESTROYED) - || !(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception))) - ) { + if (!(fiber->flags & ZEND_FIBER_FLAG_DESTROYED) || !zend_is_graceful_exit(EG(exception))) { fiber->flags |= ZEND_FIBER_FLAG_THREW; transfer->flags = ZEND_FIBER_TRANSFER_FLAG_ERROR; @@ -829,7 +827,11 @@ static void zend_fiber_object_destroy(zend_object *object) zend_rethrow_exception(EG(current_execute_data)); } - zend_exception_set_previous(EG(exception), exception); + if (exception && zend_is_unwind_exit(EG(exception))) { + OBJ_RELEASE(exception); + } else { + zend_exception_set_previous(EG(exception), exception); + } if (!EG(current_execute_data)) { zend_exception_error(EG(exception), E_ERROR); From 55ac33059dc58dc7274f32e205a75c46a5edd38c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 24 Oct 2026 11:51:19 +0100 Subject: [PATCH 2/2] rebase and apply suggestion --- Zend/zend_fibers.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index b28d0bbb383d..8c3a080f44fa 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -827,11 +827,7 @@ static void zend_fiber_object_destroy(zend_object *object) zend_rethrow_exception(EG(current_execute_data)); } - if (exception && zend_is_unwind_exit(EG(exception))) { - OBJ_RELEASE(exception); - } else { - zend_exception_set_previous(EG(exception), exception); - } + zend_exception_set_previous(EG(exception), exception); if (!EG(current_execute_data)) { zend_exception_error(EG(exception), E_ERROR);