Commit 4ddee7f5 authored by Victor Stinner's avatar Victor Stinner

Fix Py_FatalError() if called without the GIL

Issue #26558: If Py_FatalError() is called without the GIL, don't try to print
the current exception, nor try to flush stdout and stderr: only dump the
traceback of Python threads.
parent 62b6a0d7
......@@ -1241,31 +1241,62 @@ initstdio(void)
}
static void
_Py_FatalError_DumpTracebacks(int fd)
{
PyThreadState *tstate;
#ifdef WITH_THREAD
/* PyGILState_GetThisThreadState() works even if the GIL was released */
tstate = PyGILState_GetThisThreadState();
#else
tstate = PyThreadState_GET();
#endif
if (tstate == NULL) {
/* _Py_DumpTracebackThreads() requires the thread state to display
* frames */
return;
}
fputc('\n', stderr);
fflush(stderr);
/* display the current Python stack */
_Py_DumpTracebackThreads(fd, tstate->interp, tstate);
}
/* Print the current exception (if an exception is set) with its traceback,
* or display the current Python stack.
*
* Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is
* called on catastrophic cases. */
or display the current Python stack.
static void
_Py_PrintFatalError(int fd)
Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is
called on catastrophic cases.
Return 1 if the traceback was displayed, 0 otherwise. */
static int
_Py_FatalError_PrintExc(int fd)
{
PyObject *ferr, *res;
PyObject *exception, *v, *tb;
int has_tb;
PyThreadState *tstate;
if (PyThreadState_GET() == NULL) {
/* The GIL is released: trying to acquire it is likely to deadlock,
just give up. */
return 0;
}
PyErr_Fetch(&exception, &v, &tb);
if (exception == NULL) {
/* No current exception */
goto display_stack;
return 0;
}
ferr = _PySys_GetObjectId(&PyId_stderr);
if (ferr == NULL || ferr == Py_None) {
/* sys.stderr is not set yet or set to None,
no need to try to display the exception */
goto display_stack;
return 0;
}
PyErr_NormalizeException(&exception, &v, &tb);
......@@ -1276,7 +1307,7 @@ _Py_PrintFatalError(int fd)
PyException_SetTraceback(v, tb);
if (exception == NULL) {
/* PyErr_NormalizeException() failed */
goto display_stack;
return 0;
}
has_tb = (tb != Py_None);
......@@ -1292,28 +1323,9 @@ _Py_PrintFatalError(int fd)
else
Py_DECREF(res);
if (has_tb)
return;
display_stack:
#ifdef WITH_THREAD
/* PyGILState_GetThisThreadState() works even if the GIL was released */
tstate = PyGILState_GetThisThreadState();
#else
tstate = PyThreadState_GET();
#endif
if (tstate == NULL) {
/* _Py_DumpTracebackThreads() requires the thread state to display
* frames */
return;
}
fputc('\n', stderr);
fflush(stderr);
/* display the current Python stack */
_Py_DumpTracebackThreads(fd, tstate->interp, tstate);
return has_tb;
}
/* Print fatal error message and abort */
void
......@@ -1339,10 +1351,14 @@ Py_FatalError(const char *msg)
/* Print the exception (if an exception is set) with its traceback,
* or display the current Python stack. */
_Py_PrintFatalError(fd);
if (!_Py_FatalError_PrintExc(fd))
_Py_FatalError_DumpTracebacks(fd);
/* Flush sys.stdout and sys.stderr */
flush_std_files();
/* Check if the current Python thread hold the GIL */
if (PyThreadState_GET() != NULL) {
/* Flush sys.stdout and sys.stderr */
flush_std_files();
}
/* The main purpose of faulthandler is to display the traceback. We already
* did our best to display it. So faulthandler can now be disabled.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment