From d979e4335d02bee7301c2b2dec61fe2155fbae98 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sun, 9 Feb 2014 10:43:21 +1000 Subject: [PATCH] Close #20500: Don't trigger PyObject_Str assertion at shutdown --- Lib/test/test_cmd_line_script.py | 18 ++++++++++++++++++ Misc/NEWS | 5 ++++- Objects/object.c | 2 +- Python/pythonrun.c | 5 +++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 03c071e3e9a..1e6746d4341 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -405,6 +405,24 @@ class CmdLineTest(unittest.TestCase): 'stdout=%r stderr=%r' % (stdout, stderr)) self.assertEqual(0, rc) + def test_issue20500_exit_with_exception_value(self): + script = textwrap.dedent("""\ + import sys + error = None + try: + raise ValueError('some text') + except ValueError as err: + error = err + + if error: + sys.exit(error) + """) + with temp_dir() as script_dir: + script_name = _make_test_script(script_dir, 'script', script) + exitcode, stdout, stderr = assert_python_failure(script_name) + text = stderr.decode('ascii') + self.assertEqual(text, "some text") + def test_main(): support.run_unittest(CmdLineTest) diff --git a/Misc/NEWS b/Misc/NEWS index a3fef604df9..9ed7e7313dc 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,7 +10,10 @@ Release date: 2014-02-09 Core and Builtins ----------------- -- Issue #20538: UTF-7 incremental decoder produced inconsistant string when +- Issue #20500: Displaying an exception at interpreter shutdown no longer + risks triggering an assertion failure in PyObject_Str. + +- Issue #20538: UTF-7 incremental decoder produced inconsistent string when input was truncated in BASE64 section. - Issue #20404: io.TextIOWrapper (and hence the open() builtin) now uses the diff --git a/Objects/object.c b/Objects/object.c index 62bdb49d136..c634e707ba1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -508,7 +508,7 @@ PyObject_Str(PyObject *v) #ifdef Py_DEBUG /* PyObject_Str() must not be called with an exception set, because it may clear it (directly or indirectly) and so the - caller looses its exception */ + caller loses its exception */ assert(!PyErr_Occurred()); #endif diff --git a/Python/pythonrun.c b/Python/pythonrun.c index ff9569bdd2a..34a291f353e 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1792,6 +1792,11 @@ handle_system_exit(void) exitcode = (int)PyLong_AsLong(value); else { PyObject *sys_stderr = _PySys_GetObjectId(&PyId_stderr); + /* We clear the exception here to avoid triggering the assertion + * in PyObject_Str that ensures it won't silently lose exception + * details. + */ + PyErr_Clear(); if (sys_stderr != NULL && sys_stderr != Py_None) { PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); } else {