Commit afd156921e5 for php

commit afd156921e54ba889db59ae423b28721f17113b6
Author: David Carlier <devnexen@gmail.com>
Date:   Tue Oct 13 01:20:01 2026 +0100

    Fix GH-24265: zend_fiber_execute() discards exit() in a destroyed fiber

    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.

    Close GH-24285

diff --git a/NEWS b/NEWS
index b52fdfe6dc8..fb54e6dd3e6 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,8 @@ PHP                                                                        NEWS
     (David Carlier)
   . Fix function and constant imports in compile_to_ast and add support
     for grouping. (Klaas Skelte van der Werf)
+  . Fixed bug GH-24265 (Unwind/GracefulExit discarded in
+    zend_fiber_execute()). (David Carlier)

 - Date:
   . Fixed bug GH-20503 (Assertion failure with ext/date DateInterval property
diff --git a/Zend/tests/fibers/gh24265-001.phpt b/Zend/tests/fibers/gh24265-001.phpt
new file mode 100644
index 00000000000..d4eed32fc62
--- /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--
+<?php
+
+$fiber = new Fiber(function () {
+    try {
+        Fiber::suspend();
+    } finally {
+        exit(1);
+    }
+});
+
+$fiber->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 00000000000..2a794bc3d02
--- /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--
+<?php
+
+function test() {
+    $fiber = new Fiber(function () {
+        try {
+            Fiber::suspend();
+        } finally {
+            exit(1);
+        }
+    });
+
+    $fiber->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 2bebdd8d87f..8c3a080f44f 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;