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

View File

@ -379,9 +379,16 @@ handle_signals(void)
{
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();
if (PyErr_CheckSignals() < 0) {
if (_PyErr_CheckSignals() < 0) {
SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
return -1;
}