From d5d79545b73110b2f4c2b66d150409514e2ca8e0 Mon Sep 17 00:00:00 2001 From: xdegaye Date: Tue, 24 Oct 2017 16:42:33 +0200 Subject: [PATCH] [3.6] bpo-30817: Fix PyErr_PrintEx() when no memory (GH-2526). (#4107) (cherry picked from commit 66caacf2f0d6213b049a3097556e28e30440b900) --- Lib/test/test_exceptions.py | 19 ++++++++++++++++++- .../2017-07-01-15-11-13.bpo-30817.j7ZvN_.rst | 2 ++ Python/pythonrun.c | 12 +++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-07-01-15-11-13.bpo-30817.j7ZvN_.rst diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 53851cb6cf..7eb08b746c 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -10,7 +10,7 @@ import errno from test.support import (TESTFN, captured_stderr, check_impl_detail, check_warnings, cpython_only, gc_collect, run_unittest, - no_tracing, unlink, import_module) + no_tracing, unlink, import_module, script_helper) class NaiveException(Exception): def __init__(self, x): @@ -1104,6 +1104,23 @@ class ExceptionTests(unittest.TestCase): self.assertIn("test message", report) self.assertTrue(report.endswith("\n")) + @cpython_only + def test_memory_error_in_PyErr_PrintEx(self): + code = """if 1: + import _testcapi + class C(): pass + _testcapi.set_nomemory(0, %d) + C() + """ + + # Issue #30817: Abort in PyErr_PrintEx() when no memory. + # Span a large range of tests as the CPython code always evolves with + # changes that add or remove memory allocations. + for i in range(1, 20): + rc, out, err = script_helper.assert_python_failure("-c", code % i) + self.assertIn(rc, (1, 120)) + self.assertIn(b'MemoryError', err) + class ImportErrorTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-07-01-15-11-13.bpo-30817.j7ZvN_.rst b/Misc/NEWS.d/next/Core and Builtins/2017-07-01-15-11-13.bpo-30817.j7ZvN_.rst new file mode 100644 index 0000000000..f50aeefa84 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-07-01-15-11-13.bpo-30817.j7ZvN_.rst @@ -0,0 +1,2 @@ +`PyErr_PrintEx()` clears now the ignored exception that may be raised by +`_PySys_SetObjectId()`, for example when no memory. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index bf651d0ff8..6a9722bee5 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -624,9 +624,15 @@ PyErr_PrintEx(int set_sys_last_vars) return; /* Now we know v != NULL too */ if (set_sys_last_vars) { - _PySys_SetObjectId(&PyId_last_type, exception); - _PySys_SetObjectId(&PyId_last_value, v); - _PySys_SetObjectId(&PyId_last_traceback, tb); + if (_PySys_SetObjectId(&PyId_last_type, exception) < 0) { + PyErr_Clear(); + } + if (_PySys_SetObjectId(&PyId_last_value, v) < 0) { + PyErr_Clear(); + } + if (_PySys_SetObjectId(&PyId_last_traceback, tb) < 0) { + PyErr_Clear(); + } } hook = _PySys_GetObjectId(&PyId_excepthook); if (hook) { -- 2.50.1