From bdd941fac3631e0c971d6c1a4e9f9b39a787b14e Mon Sep 17 00:00:00 2001 From: Amaury Forgeot d'Arc Date: Tue, 1 Jul 2008 20:38:04 +0000 Subject: [PATCH] #3242: fix a crash in "print", if sys.stdout is set to a custom object, whose write() method installs another sys.stdout. Will backport. --- Lib/test/test_file.py | 20 +++++++++++++++++++- Misc/NEWS | 4 ++++ Python/ceval.c | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py index aab3e706cba..7cfaef76fed 100644 --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -503,13 +503,31 @@ class FileThreadingTests(unittest.TestCase): self._test_close_open_io(io_func) +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, FileSubclassTests, - FileThreadingTests) + FileThreadingTests, StdoutTests) finally: if os.path.exists(TESTFN): os.unlink(TESTFN) diff --git a/Misc/NEWS b/Misc/NEWS index af95f94affc..64b97519033 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 2.6 beta 2? 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 #3088: Corrected a race condition in classes derived from threading.local: the first member set by a thread could be saved in another thread's dictionary. diff --git a/Python/ceval.c b/Python/ceval.c index 0cff157662f..60a91b2759c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1617,9 +1617,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;