Kaydet (Commit) d979e433 authored tarafından Nick Coghlan's avatar Nick Coghlan

Close #20500: Don't trigger PyObject_Str assertion at shutdown

üst c9d1a6b8
...@@ -405,6 +405,24 @@ class CmdLineTest(unittest.TestCase): ...@@ -405,6 +405,24 @@ class CmdLineTest(unittest.TestCase):
'stdout=%r stderr=%r' % (stdout, stderr)) 'stdout=%r stderr=%r' % (stdout, stderr))
self.assertEqual(0, rc) 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(): def test_main():
support.run_unittest(CmdLineTest) support.run_unittest(CmdLineTest)
......
...@@ -10,7 +10,10 @@ Release date: 2014-02-09 ...@@ -10,7 +10,10 @@ Release date: 2014-02-09
Core and Builtins 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. input was truncated in BASE64 section.
- Issue #20404: io.TextIOWrapper (and hence the open() builtin) now uses the - Issue #20404: io.TextIOWrapper (and hence the open() builtin) now uses the
......
...@@ -508,7 +508,7 @@ PyObject_Str(PyObject *v) ...@@ -508,7 +508,7 @@ PyObject_Str(PyObject *v)
#ifdef Py_DEBUG #ifdef Py_DEBUG
/* PyObject_Str() must not be called with an exception set, /* PyObject_Str() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the because it may clear it (directly or indirectly) and so the
caller looses its exception */ caller loses its exception */
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
#endif #endif
......
...@@ -1792,6 +1792,11 @@ handle_system_exit(void) ...@@ -1792,6 +1792,11 @@ handle_system_exit(void)
exitcode = (int)PyLong_AsLong(value); exitcode = (int)PyLong_AsLong(value);
else { else {
PyObject *sys_stderr = _PySys_GetObjectId(&PyId_stderr); 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) { if (sys_stderr != NULL && sys_stderr != Py_None) {
PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW);
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment