diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2013-08-17 18:27:56 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2013-08-17 18:27:56 (GMT) |
commit | 6f6ec37838b424c5d5ccef9a640ad02b7d1cb92f (patch) | |
tree | ea727add92c9765d5e33d37a563a3d0deba30e4e | |
parent | f920a1c1f132adb10fe81ea430f08c7b61d5cc9d (diff) | |
download | cpython-6f6ec37838b424c5d5ccef9a640ad02b7d1cb92f.zip cpython-6f6ec37838b424c5d5ccef9a640ad02b7d1cb92f.tar.gz cpython-6f6ec37838b424c5d5ccef9a640ad02b7d1cb92f.tar.bz2 |
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.
-rw-r--r-- | Lib/test/test_signal.py | 41 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | 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 index 1efb5f7..0564740 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -275,6 +275,47 @@ class WakeupSignalTests(unittest.TestCase): 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 @@ -10,6 +10,10 @@ Projected Release date: 2013-09-08 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 index 0810633..bc99f23 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -175,15 +175,31 @@ checksignals_witharg(void * unused) 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; |