summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-03-24 12:46:18 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2015-03-24 12:46:18 (GMT)
commite0deff31d38f331107fd2ccd0b1f879ffc1fdb46 (patch)
tree2bc4ad64a31eeed82380c096e3371bce53baf2d2
parent454bd3a277fb725aec02c844cd8ad9af2d222fbf (diff)
parentec4f9592f5cb2c4b4bb8e2300b21d1b0e22f43e3 (diff)
downloadcpython-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.c30
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