changeset: 95154:6303795f035a parent: 95152:d6791e4026f1 parent: 95153:efb2c9ac2f88 user: Victor Stinner date: Tue Mar 24 12:01:30 2015 +0100 files: Python/pylifecycle.c Python/pythonrun.c description: (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 diff -r d6791e4026f1 -r 6303795f035a Python/pylifecycle.c --- a/Python/pylifecycle.c Tue Mar 24 12:52:13 2015 +0200 +++ b/Python/pylifecycle.c Tue Mar 24 12:01:30 2015 +0100 @@ -1244,28 +1244,74 @@ } +/* 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); - } - _PyFaulthandler_Fini(); - } + + _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 {