From ec4f9592f5cb2c4b4bb8e2300b21d1b0e22f43e3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 24 Mar 2015 13:44:35 +0100 Subject: Issue #23571: Py_FatalError() now tries to flush sys.stdout and sys.stderr It should help to see exceptions when stderr if buffered: PyErr_Display() calls sys.stderr.write(), it doesn't write into stderr file descriptor directly. --- Python/pythonrun.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 3217a9c..c16ebc4 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -586,7 +586,7 @@ Py_Finalize(void) _Py_Finalizing = tstate; initialized = 0; - /* Flush stdout+stderr */ + /* Flush sys.stdout and sys.stderr */ flush_std_files(); /* Disable signal handling */ @@ -615,7 +615,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 @@ -2596,6 +2596,7 @@ cleanup: static void _Py_PrintFatalError(int fd) { + PyObject *ferr, *res; PyObject *exception, *v, *tb; int has_tb; PyThreadState *tstate; @@ -2606,6 +2607,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; @@ -2613,7 +2621,7 @@ _Py_PrintFatalError(int fd) } PyException_SetTraceback(v, tb); if (exception == NULL) { - /* too bad, PyErr_NormalizeException() failed */ + /* PyErr_NormalizeException() failed */ goto display_stack; } @@ -2622,6 +2630,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; @@ -2651,10 +2667,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 -- cgit v0.12