Skip to content

Commit 64d6cc8

Browse files
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
1 parent 06babb2 commit 64d6cc8

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed

Include/cpython/pyerrors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause(
133133
/* In signalmodule.c */
134134

135135
int PySignal_SetWakeupFd(int fd);
136+
PyAPI_FUNC(int) _PyErr_CheckSignals(void);
136137

137138
/* Support for adding program text to SyntaxErrors */
138139

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Signal-handling is now guaranteed to happen relative to the main
2+
interpreter.

Modules/signalmodule.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class sigset_t_converter(CConverter):
9999
#include "pythread.h"
100100
static unsigned long main_thread;
101101
static pid_t main_pid;
102+
static PyInterpreterState *main_interp;
102103

103104
static volatile struct {
104105
_Py_atomic_int tripped;
@@ -185,6 +186,13 @@ itimer_retval(struct itimerval *iv)
185186
}
186187
#endif
187188

189+
static int
190+
is_main(void)
191+
{
192+
return PyThread_get_thread_ident() == main_thread &&
193+
_PyInterpreterState_Get() == main_interp;
194+
}
195+
188196
static PyObject *
189197
signal_default_int_handler(PyObject *self, PyObject *args)
190198
{
@@ -464,7 +472,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
464472
return NULL;
465473
}
466474
#endif
467-
if (PyThread_get_thread_ident() != main_thread) {
475+
if (!is_main()) {
468476
PyErr_SetString(PyExc_ValueError,
469477
"signal only works in main thread");
470478
return NULL;
@@ -486,7 +494,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
486494
else
487495
func = signal_handler;
488496
/* Check for pending signals before changing signal handler */
489-
if (PyErr_CheckSignals()) {
497+
if (_PyErr_CheckSignals()) {
490498
return NULL;
491499
}
492500
if (PyOS_setsig(signalnum, func) == SIG_ERR) {
@@ -681,7 +689,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
681689
return NULL;
682690
#endif
683691

684-
if (PyThread_get_thread_ident() != main_thread) {
692+
if (!is_main()) {
685693
PyErr_SetString(PyExc_ValueError,
686694
"set_wakeup_fd only works in main thread");
687695
return NULL;
@@ -1314,6 +1322,7 @@ PyInit__signal(void)
13141322

13151323
main_thread = PyThread_get_thread_ident();
13161324
main_pid = getpid();
1325+
main_interp = _PyInterpreterState_Get();
13171326

13181327
/* Create the module and add the functions */
13191328
m = PyModule_Create(&signalmodule);
@@ -1606,16 +1615,25 @@ finisignal(void)
16061615
/* Declared in pyerrors.h */
16071616
int
16081617
PyErr_CheckSignals(void)
1618+
{
1619+
if (!is_main()) {
1620+
return 0;
1621+
}
1622+
1623+
return _PyErr_CheckSignals();
1624+
}
1625+
1626+
1627+
/* Declared in cpython/pyerrors.h */
1628+
int
1629+
_PyErr_CheckSignals(void)
16091630
{
16101631
int i;
16111632
PyObject *f;
16121633

16131634
if (!_Py_atomic_load(&is_tripped))
16141635
return 0;
16151636

1616-
if (PyThread_get_thread_ident() != main_thread)
1617-
return 0;
1618-
16191637
/*
16201638
* The is_tripped variable is meant to speed up the calls to
16211639
* PyErr_CheckSignals (both directly or via pending calls) when no
@@ -1687,8 +1705,9 @@ int
16871705
PyOS_InterruptOccurred(void)
16881706
{
16891707
if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) {
1690-
if (PyThread_get_thread_ident() != main_thread)
1708+
if (!is_main()) {
16911709
return 0;
1710+
}
16921711
_Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0);
16931712
return 1;
16941713
}
@@ -1716,12 +1735,13 @@ _PySignal_AfterFork(void)
17161735
_clear_pending_signals();
17171736
main_thread = PyThread_get_thread_ident();
17181737
main_pid = getpid();
1738+
main_interp = _PyInterpreterState_Get();
17191739
}
17201740

17211741
int
17221742
_PyOS_IsMainThread(void)
17231743
{
1724-
return PyThread_get_thread_ident() == main_thread;
1744+
return is_main();
17251745
}
17261746

17271747
#ifdef MS_WINDOWS

Python/ceval.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,16 @@ handle_signals(void)
379379
{
380380
return 0;
381381
}
382+
/*
383+
* Ensure that the thread isn't currently running some other
384+
* interpreter.
385+
*/
386+
if (_PyInterpreterState_GET_UNSAFE() != _PyRuntime.interpreters.main) {
387+
return 0;
388+
}
382389

383390
UNSIGNAL_PENDING_SIGNALS();
384-
if (PyErr_CheckSignals() < 0) {
391+
if (_PyErr_CheckSignals() < 0) {
385392
SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
386393
return -1;
387394
}

0 commit comments

Comments
 (0)