]> granicus.if.org Git - python/commitdiff
[3.6] bpo-30817: Fix PyErr_PrintEx() when no memory (GH-2526). (#4107)
authorxdegaye <xdegaye@gmail.com>
Tue, 24 Oct 2017 14:42:33 +0000 (16:42 +0200)
committerGitHub <noreply@github.com>
Tue, 24 Oct 2017 14:42:33 +0000 (16:42 +0200)
(cherry picked from commit 66caacf2f0d6213b049a3097556e28e30440b900)

Lib/test/test_exceptions.py
Misc/NEWS.d/next/Core and Builtins/2017-07-01-15-11-13.bpo-30817.j7ZvN_.rst [new file with mode: 0644]
Python/pythonrun.c

index 53851cb6cfda660c0eedb55e0264d5b792abf87d..7eb08b746c0a46006b705b1092ba0b4132fe8e3b 100644 (file)
@@ -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 (file)
index 0000000..f50aeef
--- /dev/null
@@ -0,0 +1,2 @@
+`PyErr_PrintEx()` clears now the ignored exception that may be raised by
+`_PySys_SetObjectId()`, for example when no memory.
index bf651d0ff8d5e18be3371d61a2cce716322aa044..6a9722bee5f5dfe36429b64b85e7c10ad2e9a686 100644 (file)
@@ -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) {