mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-43406: Fix possible race condition where `PyErr_CheckSignals
` tries to execute a non-Python signal handler (GH-24756)
We can receive signals (at the C level, in `trip_signal()` in signalmodule.c) while `signal.signal` is being called to modify the corresponding handler. Later when `PyErr_CheckSignals()` is called to handle the given signal, the handler may be a non-callable object and would raise a cryptic asynchronous exception.
This commit is contained in:
parent
02ac6f41e5
commit
68245b7a10
3 changed files with 77 additions and 1 deletions
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue