Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d7c8fbf

Browse files
committed
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.
1 parent fb36b3f commit d7c8fbf

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

Lib/test/test_cmd_line.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,25 @@ def test_unmached_quote(self):
272272
self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError')
273273
self.assertEqual(b'', out)
274274

275+
def test_stdout_flush_at_shutdown(self):
276+
# Issue #5319: if stdout.flush() fails at shutdown, an error should
277+
# be printed out.
278+
code = """if 1:
279+
import os, sys
280+
sys.stdout.write('x')
281+
os.close(sys.stdout.fileno())"""
282+
rc, out, err = assert_python_ok('-c', code)
283+
self.assertEqual(b'', out)
284+
self.assertRegex(err.decode('ascii', 'ignore'),
285+
'Exception IOError: .* ignored')
286+
287+
def test_closed_stdout(self):
288+
# Issue #13444: if stdout has been explicitly closed, we should
289+
# not attempt to flush it at shutdown.
290+
code = "import sys; sys.stdout.close()"
291+
rc, out, err = assert_python_ok('-c', code)
292+
self.assertEqual(b'', err)
293+
275294

276295
def test_main():
277296
test.support.run_unittest(CmdLineTest)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ Core and Builtins
8383
Library
8484
-------
8585

86+
- Issue #13444: When stdout has been closed explicitly, we should not attempt
87+
to flush it at shutdown and print an error.
88+
8689
- Issue #12856: Ensure child processes do not inherit the parent's random
8790
seed for filename generation in the tempfile module. Patch by Brian
8891
Harring.

Python/pythonrun.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,22 +332,38 @@ extern void dump_counts(FILE*);
332332

333333
/* Flush stdout and stderr */
334334

335+
static int
336+
file_is_closed(PyObject *fobj)
337+
{
338+
int r;
339+
PyObject *tmp = PyObject_GetAttrString(fobj, "closed");
340+
if (tmp == NULL) {
341+
PyErr_Clear();
342+
return 0;
343+
}
344+
r = PyObject_IsTrue(tmp);
345+
Py_DECREF(tmp);
346+
if (r < 0)
347+
PyErr_Clear();
348+
return r > 0;
349+
}
350+
335351
static void
336352
flush_std_files(void)
337353
{
338354
PyObject *fout = PySys_GetObject("stdout");
339355
PyObject *ferr = PySys_GetObject("stderr");
340356
PyObject *tmp;
341357

342-
if (fout != NULL && fout != Py_None) {
358+
if (fout != NULL && fout != Py_None && !file_is_closed(fout)) {
343359
tmp = PyObject_CallMethod(fout, "flush", "");
344360
if (tmp == NULL)
345361
PyErr_WriteUnraisable(fout);
346362
else
347363
Py_DECREF(tmp);
348364
}
349365

350-
if (ferr != NULL && ferr != Py_None) {
366+
if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) {
351367
tmp = PyObject_CallMethod(ferr, "flush", "");
352368
if (tmp == NULL)
353369
PyErr_Clear();

0 commit comments

Comments
 (0)