bpo-35724: Explicitly require the main interpreter for signal-handling. (GH-11530)

Ensure that the main interpreter is active (in the main thread) for signal-handling operations. This is increasingly relevant as people use subinterpreters more.

https://bugs.python.org/issue35724
This commit is contained in:
Eric Snow 2019-02-23 15:40:43 -07:00 committed by GitHub
parent 06babb2422
commit 64d6cc826d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 9 deletions

View File

@ -133,6 +133,7 @@ PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause(
/* In signalmodule.c */ /* In signalmodule.c */
int PySignal_SetWakeupFd(int fd); int PySignal_SetWakeupFd(int fd);
PyAPI_FUNC(int) _PyErr_CheckSignals(void);
/* Support for adding program text to SyntaxErrors */ /* Support for adding program text to SyntaxErrors */

View File

@ -0,0 +1,2 @@
Signal-handling is now guaranteed to happen relative to the main
interpreter.

View File

@ -99,6 +99,7 @@ class sigset_t_converter(CConverter):
#include "pythread.h" #include "pythread.h"
static unsigned long main_thread; static unsigned long main_thread;
static pid_t main_pid; static pid_t main_pid;
static PyInterpreterState *main_interp;
static volatile struct { static volatile struct {
_Py_atomic_int tripped; _Py_atomic_int tripped;
@ -185,6 +186,13 @@ itimer_retval(struct itimerval *iv)
} }
#endif #endif
static int
is_main(void)
{
return PyThread_get_thread_ident() == main_thread &&
_PyInterpreterState_Get() == main_interp;
}
static PyObject * static PyObject *
signal_default_int_handler(PyObject *self, PyObject *args) signal_default_int_handler(PyObject *self, PyObject *args)
{ {
@ -464,7 +472,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
return NULL; return NULL;
} }
#endif #endif
if (PyThread_get_thread_ident() != main_thread) { if (!is_main()) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"signal only works in main thread"); "signal only works in main thread");
return NULL; return NULL;
@ -486,7 +494,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
else else
func = signal_handler; func = signal_handler;
/* Check for pending signals before changing signal handler */ /* Check for pending signals before changing signal handler */
if (PyErr_CheckSignals()) { if (_PyErr_CheckSignals()) {
return NULL; return NULL;
} }
if (PyOS_setsig(signalnum, func) == SIG_ERR) { if (PyOS_setsig(signalnum, func) == SIG_ERR) {
@ -681,7 +689,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
return NULL; return NULL;
#endif #endif
if (PyThread_get_thread_ident() != main_thread) { if (!is_main()) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"set_wakeup_fd only works in main thread"); "set_wakeup_fd only works in main thread");
return NULL; return NULL;
@ -1314,6 +1322,7 @@ PyInit__signal(void)
main_thread = PyThread_get_thread_ident(); main_thread = PyThread_get_thread_ident();
main_pid = getpid(); main_pid = getpid();
main_interp = _PyInterpreterState_Get();
/* Create the module and add the functions */ /* Create the module and add the functions */
m = PyModule_Create(&signalmodule); m = PyModule_Create(&signalmodule);
@ -1606,6 +1615,18 @@ finisignal(void)
/* Declared in pyerrors.h */ /* Declared in pyerrors.h */
int int
PyErr_CheckSignals(void) PyErr_CheckSignals(void)
{
if (!is_main()) {
return 0;
}
return _PyErr_CheckSignals();
}
/* Declared in cpython/pyerrors.h */
int
_PyErr_CheckSignals(void)
{ {
int i; int i;
PyObject *f; PyObject *f;
@ -1613,9 +1634,6 @@ PyErr_CheckSignals(void)
if (!_Py_atomic_load(&is_tripped)) if (!_Py_atomic_load(&is_tripped))
return 0; return 0;
if (PyThread_get_thread_ident() != main_thread)
return 0;
/* /*
* The is_tripped variable is meant to speed up the calls to * The is_tripped variable is meant to speed up the calls to
* PyErr_CheckSignals (both directly or via pending calls) when no * PyErr_CheckSignals (both directly or via pending calls) when no
@ -1687,8 +1705,9 @@ int
PyOS_InterruptOccurred(void) PyOS_InterruptOccurred(void)
{ {
if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) { if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) {
if (PyThread_get_thread_ident() != main_thread) if (!is_main()) {
return 0; return 0;
}
_Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0); _Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0);
return 1; return 1;
} }
@ -1716,12 +1735,13 @@ _PySignal_AfterFork(void)
_clear_pending_signals(); _clear_pending_signals();
main_thread = PyThread_get_thread_ident(); main_thread = PyThread_get_thread_ident();
main_pid = getpid(); main_pid = getpid();
main_interp = _PyInterpreterState_Get();
} }
int int
_PyOS_IsMainThread(void) _PyOS_IsMainThread(void)
{ {
return PyThread_get_thread_ident() == main_thread; return is_main();
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS

View File

@ -379,9 +379,16 @@ handle_signals(void)
{ {
return 0; return 0;
} }
/*
* Ensure that the thread isn't currently running some other
* interpreter.
*/
if (_PyInterpreterState_GET_UNSAFE() != _PyRuntime.interpreters.main) {
return 0;
}
UNSIGNAL_PENDING_SIGNALS(); UNSIGNAL_PENDING_SIGNALS();
if (PyErr_CheckSignals() < 0) { if (_PyErr_CheckSignals() < 0) {
SIGNAL_PENDING_SIGNALS(); /* We're not done yet */ SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
return -1; return -1;
} }