Commit 296fad10fb4 for php.net
commit 296fad10fb4e1a572ec05269bc798f68cddc72fa
Author: David Carlier <devnexen@gmail.com>
Date: Thu Feb 19 20:07:44 2026 +0000
ext/pcntl: fix pcntl_signal_dispatch() stale tail pointer and exception handling.
close GH-21259
diff --git a/NEWS b/NEWS
index 6a1388a961c..28187bd8590 100644
--- a/NEWS
+++ b/NEWS
@@ -50,6 +50,8 @@ PHP NEWS
on NetBSD/Solaris platforms. (David Carlier)
. Fixed pcntl_signal() signal table registering the callback first
OS-wise before the internal list. (David Carlier)
+ . Fixed pcntl_signal_dispatch() stale pointer and exception
+ handling. (David Carlier)
- PDO_PGSQL:
. Fixed bug GH-21055 (connection attribute status typo for GSS negotiation).
diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c
index de8d7dfecfd..082bdc4ba90 100644
--- a/ext/pcntl/pcntl.c
+++ b/ext/pcntl/pcntl.c
@@ -1343,6 +1343,7 @@ void pcntl_signal_dispatch(void)
queue = PCNTL_G(head);
PCNTL_G(head) = NULL; /* simple stores are atomic */
+ PCNTL_G(tail) = NULL;
/* Allocate */
while (queue) {
@@ -1364,6 +1365,9 @@ void pcntl_signal_dispatch(void)
#ifdef HAVE_STRUCT_SIGINFO_T
zval_ptr_dtor(¶ms[1]);
#endif
+ if (EG(exception)) {
+ break;
+ }
}
}
@@ -1373,6 +1377,14 @@ void pcntl_signal_dispatch(void)
queue = next;
}
+ /* drain the remaining in case of exception thrown */
+ while (queue) {
+ next = queue->next;
+ queue->next = PCNTL_G(spares);
+ PCNTL_G(spares) = queue;
+ queue = next;
+ }
+
PCNTL_G(pending_signals) = 0;
/* Re-enable queue */
diff --git a/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt b/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt
new file mode 100644
index 00000000000..06c4f827c6e
--- /dev/null
+++ b/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt
@@ -0,0 +1,34 @@
+--TEST--
+pcntl_signal_dispatch() stops dispatching after handler throws exception
+--EXTENSIONS--
+pcntl
+posix
+--FILE--
+<?php
+
+$called = [];
+
+pcntl_signal(SIGUSR1, function ($signo) use (&$called) {
+ $called[] = 'SIGUSR1';
+ throw new \Exception('Exception in signal handler');
+});
+
+pcntl_signal(SIGUSR2, function ($signo) use (&$called) {
+ $called[] = 'SIGUSR2';
+});
+
+posix_kill(posix_getpid(), SIGUSR1);
+posix_kill(posix_getpid(), SIGUSR2);
+
+try {
+ pcntl_signal_dispatch();
+} catch (\Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+echo "Handlers called: " . implode(', ', $called) . "\n";
+
+?>
+--EXPECT--
+Exception in signal handler
+Handlers called: SIGUSR1