mirror of https://github.com/python/cpython
(Merge 3.4) Issue #23571: Enhance Py_FatalError()
* Display the current Python stack if an exception was raised but the exception has no traceback * Disable faulthandler if an exception was raised (before it was only disabled if no exception was raised) * To display the current Python stack, call PyGILState_GetThisThreadState() which works even if the GIL was released
This commit is contained in:
commit
10dc48497e
|
@ -1244,28 +1244,74 @@ initstdio(void)
|
|||
}
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
||||
static void
|
||||
_Py_PrintFatalError(int fd)
|
||||
{
|
||||
PyObject *exception, *v, *tb;
|
||||
int has_tb;
|
||||
PyThreadState *tstate;
|
||||
|
||||
PyErr_Fetch(&exception, &v, &tb);
|
||||
if (exception == NULL) {
|
||||
/* No current exception */
|
||||
goto display_stack;
|
||||
}
|
||||
|
||||
PyErr_NormalizeException(&exception, &v, &tb);
|
||||
if (tb == NULL) {
|
||||
tb = Py_None;
|
||||
Py_INCREF(tb);
|
||||
}
|
||||
PyException_SetTraceback(v, tb);
|
||||
if (exception == NULL) {
|
||||
/* too bad, PyErr_NormalizeException() failed */
|
||||
goto display_stack;
|
||||
}
|
||||
|
||||
has_tb = (tb != NULL && tb != Py_None);
|
||||
PyErr_Display(exception, v, tb);
|
||||
Py_XDECREF(exception);
|
||||
Py_XDECREF(v);
|
||||
Py_XDECREF(tb);
|
||||
if (has_tb)
|
||||
return;
|
||||
|
||||
display_stack:
|
||||
/* PyGILState_GetThisThreadState() works even if the GIL was released */
|
||||
tstate = PyGILState_GetThisThreadState();
|
||||
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 fatal error message and abort */
|
||||
|
||||
void
|
||||
Py_FatalError(const char *msg)
|
||||
{
|
||||
const int fd = fileno(stderr);
|
||||
PyThreadState *tstate;
|
||||
|
||||
fprintf(stderr, "Fatal Python error: %s\n", msg);
|
||||
fflush(stderr); /* it helps in Windows debug build */
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_PrintEx(0);
|
||||
}
|
||||
else {
|
||||
tstate = (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current);
|
||||
if (tstate != NULL) {
|
||||
fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
_Py_DumpTracebackThreads(fd, tstate->interp, tstate);
|
||||
}
|
||||
|
||||
_Py_PrintFatalError(fd);
|
||||
|
||||
/* The main purpose of faulthandler is to display the traceback. We already
|
||||
* did our best to display it. So faulthandler can now be disabled. */
|
||||
_PyFaulthandler_Fini();
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue