diff options
Diffstat (limited to 'Modules/signalmodule.c')
-rw-r--r-- | Modules/signalmodule.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 7ac797a..c6564be 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1706,10 +1706,34 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate) } _Py_atomic_store_relaxed(&Handlers[i].tripped, 0); + /* Signal handlers can be modified while a signal is received, + * and therefore the fact that trip_signal() or PyErr_SetInterrupt() + * was called doesn't guarantee that there is still a Python + * signal handler for it by the time PyErr_CheckSignals() is called + * (see bpo-43406). + */ + PyObject *func = Handlers[i].func; + if (func == NULL || func == Py_None || func == IgnoreHandler || + func == DefaultHandler) { + /* No Python signal handler due to aforementioned race condition. + * We can't call raise() as it would break the assumption + * that PyErr_SetInterrupt() only *simulates* an incoming + * signal (i.e. it will never kill the process). + * We also don't want to interrupt user code with a cryptic + * asynchronous exception, so instead just write out an + * unraisable error. + */ + PyErr_Format(PyExc_OSError, + "Signal %i ignored due to race condition", + i); + PyErr_WriteUnraisable(Py_None); + continue; + } + PyObject *arglist = Py_BuildValue("(iO)", i, frame); PyObject *result; if (arglist) { - result = _PyObject_Call(tstate, Handlers[i].func, arglist, NULL); + result = _PyObject_Call(tstate, func, arglist, NULL); Py_DECREF(arglist); } else { |