Close #20500: Don't trigger PyObject_Str assertion at shutdown
authorNick Coghlan <ncoghlan@gmail.com>
Sun, 9 Feb 2014 00:43:21 +0000 (10:43 +1000)
committerNick Coghlan <ncoghlan@gmail.com>
Sun, 9 Feb 2014 00:43:21 +0000 (10:43 +1000)
Lib/test/test_cmd_line_script.py
Misc/NEWS
Objects/object.c
Python/pythonrun.c

index 03c071e3e9a0d1725300bc52d2a3f7aaf38673e0..1e6746d43416c3823dcb6b3b3dd0237f1ebe8631 100644 (file)
@@ -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)
index a3fef604df9092ec63bf946ca5abbfd25bdebf62..9ed7e7313dcfa9235fea2bc5dd1fb64c541b59ea 100644 (file)
--- 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
index 62bdb49d13667b03175addb9ff6041b16c081300..c634e707ba1e7a101fec10c26ca487a3b0b07a30 100644 (file)
@@ -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
 
index ff9569bdd2aea1c25d890ae1939bff3f4fcd456e..34a291f353ef52a7f2ff69b5cbfad2111a351570 100644 (file)
@@ -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 {