]> granicus.if.org Git - php/commitdiff
Fixed bug #73783
authorDavid Walker <dave@mudsite.com>
Mon, 19 Dec 2016 21:29:18 +0000 (14:29 -0700)
committerNikita Popov <nikic@php.net>
Thu, 29 Dec 2016 20:18:22 +0000 (21:18 +0100)
Bug #73783 raises an issue with signal handling when using SIG_IGN.
With PHP7.1 ZEND_SIGNALS is defaulted to on, which will for all
signals set the handler as zend_signal_handler_defer.  This is
problematic for syscalls like sleep(), which will only return when the
requisite number of seconds have elapsed, or, a non-ignored signal is
raised.  In this case we want to SIG_IGN SIGCHLD, however, SIG_IGN is
only stored in the SIGG(handlers) array, and the actual system level
handler is defined.  This prevents proper signal ignoring when requeted.

NEWS
Zend/zend_signal.c
ext/pcntl/tests/bug73783.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 05492132b93dc4979c61911d633cccdfc5278088..9d1a2c5bc9a94199225990e01a0158768a0e6466 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ PHP                                                                        NEWS
   . Fixed bug #73727 (ZEND_MM_BITSET_LEN is "undefined symbol" in
     zend_bitset.h). (Nikita)
   . Fixed bug #73753 (unserialized array pointer not advancing). (David Walker)
+  . Fixed bug #73783 (SIG_IGN doesn't work when Zend Signals is enabled).
+    (David Walker)
 
 - CLI:
   . Fixed bug #72555 (CLI output(japanese) on Windows). (Anatol)
index 1d8baaf0f529dae514056447b2c30bbc1b4ba690..605187aed25bb4895bd9c2cb7229df4bd3274369 100644 (file)
@@ -198,7 +198,7 @@ static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context)
 #endif
                        }
                }
-       } else if (p_sig.handler != SIG_IGN) { /* ignore SIG_IGN */
+       } else {
                if (p_sig.flags & SA_SIGINFO) {
                        if (p_sig.flags & SA_RESETHAND) {
                                SIGG(handlers)[signo-1].flags   = 0;
@@ -234,9 +234,13 @@ ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigac
                }
 
                memset(&sa, 0, sizeof(sa));
-               sa.sa_flags     = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK);
-               sa.sa_sigaction = zend_signal_handler_defer;
-               sa.sa_mask      = global_sigmask;
+               if (SIGG(handlers)[signo-1].handler == (void *) SIG_IGN) {
+                       sa.sa_sigaction = (void *) SIG_IGN;
+               } else {
+                       sa.sa_flags     = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK);
+                       sa.sa_sigaction = zend_signal_handler_defer;
+                       sa.sa_mask      = global_sigmask;
+               }
 
                if (sigaction(signo, &sa, NULL) < 0) {
                        zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo);
diff --git a/ext/pcntl/tests/bug73783.phpt b/ext/pcntl/tests/bug73783.phpt
new file mode 100644 (file)
index 0000000..beacdf6
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+Bug #73783: (SIG_IGN needs to be set to prevent syscals from returning early)
+--SKIPIF--
+<?php
+       if (!extension_loaded('pcntl')) die('skip pcntl extension not available');
+       elseif (!extension_loaded('posix')) die('skip posix extension not available');
+?>
+--FILE--
+<?php
+pcntl_signal(SIGCHLD, SIG_IGN);
+
+switch(pcntl_fork()) {
+    case 0:
+        exit;
+        break;
+}
+
+$before = microtime(true);
+sleep(1);
+
+if (microtime(true) - $before >= 0.8) {
+    echo "working\n";
+} else {
+    echo "failed\n";
+}
+?>
+--EXPECTF--
+working