diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ef7d25e9ca9..d611c7a5d81 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -546,7 +546,7 @@ Py_Finalize(void) _Py_Finalizing = tstate; initialized = 0; - /* Flush stdout+stderr */ + /* Flush sys.stdout and sys.stderr */ flush_std_files(); /* Disable signal handling */ @@ -575,7 +575,7 @@ Py_Finalize(void) /* Destroy all modules */ PyImport_Cleanup(); - /* Flush stdout+stderr (again, in case more was printed) */ + /* Flush sys.stdout and sys.stderr (again, in case more was printed) */ flush_std_files(); /* Collect final garbage. This disposes of cycles created by @@ -1253,6 +1253,7 @@ initstdio(void) static void _Py_PrintFatalError(int fd) { + PyObject *ferr, *res; PyObject *exception, *v, *tb; int has_tb; PyThreadState *tstate; @@ -1263,6 +1264,13 @@ _Py_PrintFatalError(int fd) goto display_stack; } + 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; + } + PyErr_NormalizeException(&exception, &v, &tb); if (tb == NULL) { tb = Py_None; @@ -1270,7 +1278,7 @@ _Py_PrintFatalError(int fd) } PyException_SetTraceback(v, tb); if (exception == NULL) { - /* too bad, PyErr_NormalizeException() failed */ + /* PyErr_NormalizeException() failed */ goto display_stack; } @@ -1279,6 +1287,14 @@ _Py_PrintFatalError(int fd) Py_XDECREF(exception); Py_XDECREF(v); Py_XDECREF(tb); + + /* sys.stderr may be buffered: call sys.stderr.flush() */ + res = _PyObject_CallMethodId(ferr, &PyId_flush, ""); + if (res == NULL) + PyErr_Clear(); + else + Py_DECREF(res); + if (has_tb) return; @@ -1307,10 +1323,16 @@ Py_FatalError(const char *msg) fprintf(stderr, "Fatal Python error: %s\n", msg); fflush(stderr); /* it helps in Windows debug build */ + /* Print the exception (if an exception is set) with its traceback, + * or display the current Python stack. */ _Py_PrintFatalError(fd); + /* 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. */ + * did our best to display it. So faulthandler can now be disabled. + * (Don't trigger it on abort().) */ _PyFaulthandler_Fini(); #ifdef MS_WINDOWS