diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-24 11:01:30 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-24 11:01:30 (GMT) |
commit | 10dc48497e9c79d253bd0861b5f41843a114f146 (patch) | |
tree | 56b95bf12c90f9d542bd26935b45812f06b061b1 /Python | |
parent | 0f05cea05773d0810db6219cd1430d8c46d29a3b (diff) | |
parent | 0e98a76b65161b74a23f64e05a8075b46d908d10 (diff) | |
download | cpython-10dc48497e9c79d253bd0861b5f41843a114f146.zip cpython-10dc48497e9c79d253bd0861b5f41843a114f146.tar.gz cpython-10dc48497e9c79d253bd0861b5f41843a114f146.tar.bz2 |
(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
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pylifecycle.c | 72 |
1 files changed, 59 insertions, 13 deletions
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 2a36b53..ef7d25e 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -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); - } - _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 { |