[Python-checkins] cpython: Issue #16105: When a signal handler fails to write to the file descriptor

antoine.pitrou python-checkins at python.org
Sat Aug 17 20:33:11 CEST 2013


http://hg.python.org/cpython/rev/e2b234f5bf7d
changeset:   85239:e2b234f5bf7d
parent:      85237:5c091acc799f
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Sat Aug 17 20:27:56 2013 +0200
summary:
  Issue #16105: When a signal handler fails to write to the file descriptor registered with ``signal.set_wakeup_fd()``, report an exception instead of ignoring the error.

files:
  Lib/test/test_signal.py |  41 +++++++++++++++++++++++++++++
  Misc/NEWS               |   4 ++
  Modules/signalmodule.c  |  18 ++++++++++++-
  3 files changed, 62 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -275,6 +275,47 @@
 
         assert_python_ok('-c', code)
 
+    def test_wakeup_write_error(self):
+        # Issue #16105: write() errors in the C signal handler should not
+        # pass silently.
+        # Use a subprocess to have only one thread.
+        code = """if 1:
+        import errno
+        import fcntl
+        import os
+        import signal
+        import sys
+        import time
+        from test.support import captured_stderr
+
+        def handler(signum, frame):
+            1/0
+
+        signal.signal(signal.SIGALRM, handler)
+        r, w = os.pipe()
+        flags = fcntl.fcntl(r, fcntl.F_GETFL, 0)
+        fcntl.fcntl(r, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+
+        # Set wakeup_fd a read-only file descriptor to trigger the error
+        signal.set_wakeup_fd(r)
+        try:
+            with captured_stderr() as err:
+                signal.alarm(1)
+                time.sleep(5.0)
+        except ZeroDivisionError:
+            # An ignored exception should have been printed out on stderr
+            err = err.getvalue()
+            if ('Exception ignored when trying to write to the signal wakeup fd'
+                not in err):
+                raise AssertionError(err)
+            if ('OSError: [Errno %d]' % errno.EBADF) not in err:
+                raise AssertionError(err)
+        else:
+            raise AssertionError("ZeroDivisionError not raised")
+        """
+
+        assert_python_ok('-c', code)
+
     def test_wakeup_fd_early(self):
         self.check_wakeup("""def test():
             import select
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@
 Core and Builtins
 -----------------
 
+- Issue #16105: When a signal handler fails to write to the file descriptor
+  registered with ``signal.set_wakeup_fd()``, report an exception instead
+  of ignoring the error.
+
 - Issue #18722: Remove uses of the "register" keyword in C code.
 
 - Issue #18667: Add missing "HAVE_FCHOWNAT" symbol to posix._have_functions.
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -175,15 +175,31 @@
     return PyErr_CheckSignals();
 }
 
+static int
+report_wakeup_error(void *data)
+{
+    int save_errno = errno;
+    errno = (int) (Py_intptr_t) data;
+    PyErr_SetFromErrno(PyExc_OSError);
+    PySys_WriteStderr("Exception ignored when trying to write to the "
+                      "signal wakeup fd:\n");
+    PyErr_WriteUnraisable(NULL);
+    errno = save_errno;
+    return 0;
+}
+
 static void
 trip_signal(int sig_num)
 {
     unsigned char byte;
+    int rc = 0;
 
     Handlers[sig_num].tripped = 1;
     if (wakeup_fd != -1) {
         byte = (unsigned char)sig_num;
-        write(wakeup_fd, &byte, 1);
+        while ((rc = write(wakeup_fd, &byte, 1)) == -1 && errno == EINTR);
+        if (rc == -1)
+            Py_AddPendingCall(report_wakeup_error, (void *) (Py_intptr_t) errno);
     }
     if (is_tripped)
         return;

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list