diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py index 73cb5b24127..0a8114a0c7b 100644 --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -323,11 +323,30 @@ class OtherFileTests(unittest.TestCase): os.unlink(TESTFN) +class StdoutTests(unittest.TestCase): + + def test_move_stdout_on_write(self): + # Issue 3242: sys.stdout can be replaced (and freed) during a + # print statement; prevent a segfault in this case + save_stdout = sys.stdout + + class File: + def write(self, data): + if '\n' in data: + sys.stdout = save_stdout + + try: + sys.stdout = File() + print "some text" + finally: + sys.stdout = save_stdout + + def test_main(): # Historically, these tests have been sloppy about removing TESTFN. # So get rid of it no matter what. try: - run_unittest(AutoFileTests, OtherFileTests) + run_unittest(AutoFileTests, OtherFileTests, StdoutTests) finally: if os.path.exists(TESTFN): os.unlink(TESTFN) diff --git a/Misc/NEWS b/Misc/NEWS index 27c12c1425a..4d6dd8344bc 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ What's New in Python 2.5.3? Core and builtins ----------------- +- Issue #3242: Fix a crash inside the print statement, if sys.stdout is + set to a custom object whose write() method happens to install + another file in sys.stdout. + - Issue #3100: Corrected a crash on deallocation of a subclassed weakref which holds the last (strong) reference to its referent. diff --git a/Python/ceval.c b/Python/ceval.c index 06d524b275d..9bc147b78d8 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1603,9 +1603,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) "lost sys.stdout"); } if (w != NULL) { + Py_INCREF(w); err = PyFile_WriteString("\n", w); if (err == 0) PyFile_SoftSpace(w, 0); + Py_DECREF(w); } Py_XDECREF(stream); stream = NULL;