Issue #13444: When stdout has been closed explicitly, we should not attempt to flush it at shutdown and print an error.

This also adds a test for issue #5319, whose resolution introduced the issue.
This commit is contained in:
Antoine Pitrou 2011-11-26 21:59:36 +01:00
parent fb36b3f6a0
commit d7c8fbf89e
3 changed files with 40 additions and 2 deletions

View file

@ -272,6 +272,25 @@ class CmdLineTest(unittest.TestCase):
self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError') self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError')
self.assertEqual(b'', out) self.assertEqual(b'', out)
def test_stdout_flush_at_shutdown(self):
# Issue #5319: if stdout.flush() fails at shutdown, an error should
# be printed out.
code = """if 1:
import os, sys
sys.stdout.write('x')
os.close(sys.stdout.fileno())"""
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(b'', out)
self.assertRegex(err.decode('ascii', 'ignore'),
'Exception IOError: .* ignored')
def test_closed_stdout(self):
# Issue #13444: if stdout has been explicitly closed, we should
# not attempt to flush it at shutdown.
code = "import sys; sys.stdout.close()"
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(b'', err)
def test_main(): def test_main():
test.support.run_unittest(CmdLineTest) test.support.run_unittest(CmdLineTest)

View file

@ -83,6 +83,9 @@ Core and Builtins
Library Library
------- -------
- Issue #13444: When stdout has been closed explicitly, we should not attempt
to flush it at shutdown and print an error.
- Issue #12856: Ensure child processes do not inherit the parent's random - Issue #12856: Ensure child processes do not inherit the parent's random
seed for filename generation in the tempfile module. Patch by Brian seed for filename generation in the tempfile module. Patch by Brian
Harring. Harring.

View file

@ -332,6 +332,22 @@ extern void dump_counts(FILE*);
/* Flush stdout and stderr */ /* Flush stdout and stderr */
static int
file_is_closed(PyObject *fobj)
{
int r;
PyObject *tmp = PyObject_GetAttrString(fobj, "closed");
if (tmp == NULL) {
PyErr_Clear();
return 0;
}
r = PyObject_IsTrue(tmp);
Py_DECREF(tmp);
if (r < 0)
PyErr_Clear();
return r > 0;
}
static void static void
flush_std_files(void) flush_std_files(void)
{ {
@ -339,7 +355,7 @@ flush_std_files(void)
PyObject *ferr = PySys_GetObject("stderr"); PyObject *ferr = PySys_GetObject("stderr");
PyObject *tmp; PyObject *tmp;
if (fout != NULL && fout != Py_None) { if (fout != NULL && fout != Py_None && !file_is_closed(fout)) {
tmp = PyObject_CallMethod(fout, "flush", ""); tmp = PyObject_CallMethod(fout, "flush", "");
if (tmp == NULL) if (tmp == NULL)
PyErr_WriteUnraisable(fout); PyErr_WriteUnraisable(fout);
@ -347,7 +363,7 @@ flush_std_files(void)
Py_DECREF(tmp); Py_DECREF(tmp);
} }
if (ferr != NULL && ferr != Py_None) { if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) {
tmp = PyObject_CallMethod(ferr, "flush", ""); tmp = PyObject_CallMethod(ferr, "flush", "");
if (tmp == NULL) if (tmp == NULL)
PyErr_Clear(); PyErr_Clear();