summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-03-24 10:24:06 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2015-03-24 10:24:06 (GMT)
commit0e98a76b65161b74a23f64e05a8075b46d908d10 (patch)
tree0a997ce4fe390468530efbbc88c8d9dafd21346c
parent2e3998fae0996bbb349a4696071f0582f8c799c0 (diff)
downloadcpython-0e98a76b65161b74a23f64e05a8075b46d908d10.zip
cpython-0e98a76b65161b74a23f64e05a8075b46d908d10.tar.gz
cpython-0e98a76b65161b74a23f64e05a8075b46d908d10.tar.bz2
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
-rw-r--r--Python/pythonrun.c73
1 files changed, 60 insertions, 13 deletions
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 0327830..3217a9c 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -2587,28 +2587,75 @@ cleanup:
}
}
+/* 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 = _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
{