diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-24 12:46:18 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-24 12:46:18 (GMT) |
commit | e0deff31d38f331107fd2ccd0b1f879ffc1fdb46 (patch) | |
tree | 2bc4ad64a31eeed82380c096e3371bce53baf2d2 | |
parent | 454bd3a277fb725aec02c844cd8ad9af2d222fbf (diff) | |
parent | ec4f9592f5cb2c4b4bb8e2300b21d1b0e22f43e3 (diff) | |
download | cpython-e0deff31d38f331107fd2ccd0b1f879ffc1fdb46.zip cpython-e0deff31d38f331107fd2ccd0b1f879ffc1fdb46.tar.gz cpython-e0deff31d38f331107fd2ccd0b1f879ffc1fdb46.tar.bz2 |
(Merge 3.4) 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.
-rw-r--r-- | Python/pylifecycle.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ef7d25e..d611c7a 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 |