Commit 6f6ec378 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #16105: When a signal handler fails to write to the file descriptor...

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.
parent f920a1c1
...@@ -275,6 +275,47 @@ class WakeupSignalTests(unittest.TestCase): ...@@ -275,6 +275,47 @@ class WakeupSignalTests(unittest.TestCase):
assert_python_ok('-c', code) 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): def test_wakeup_fd_early(self):
self.check_wakeup("""def test(): self.check_wakeup("""def test():
import select import select
......
...@@ -10,6 +10,10 @@ Projected Release date: 2013-09-08 ...@@ -10,6 +10,10 @@ Projected Release date: 2013-09-08
Core and Builtins 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 #18722: Remove uses of the "register" keyword in C code.
- Issue #18667: Add missing "HAVE_FCHOWNAT" symbol to posix._have_functions. - Issue #18667: Add missing "HAVE_FCHOWNAT" symbol to posix._have_functions.
......
...@@ -175,15 +175,31 @@ checksignals_witharg(void * unused) ...@@ -175,15 +175,31 @@ checksignals_witharg(void * unused)
return PyErr_CheckSignals(); 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 static void
trip_signal(int sig_num) trip_signal(int sig_num)
{ {
unsigned char byte; unsigned char byte;
int rc = 0;
Handlers[sig_num].tripped = 1; Handlers[sig_num].tripped = 1;
if (wakeup_fd != -1) { if (wakeup_fd != -1) {
byte = (unsigned char)sig_num; 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) if (is_tripped)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment