rc, _, err = script_helper.assert_python_ok("-c", code)
self.assertIn(b'MemoryError', err)
+ @cpython_only
+ # Python built with Py_TRACE_REFS fail with a fatal error in
+ # _PyRefchain_Trace() on memory allocation error.
+ @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build')
+ def test_exec_set_nomemory_hang(self):
+ import_module("_testcapi")
+ # gh-134163: A MemoryError inside code that was wrapped by a try/except
+ # block would lead to an infinite loop.
+
+ # The frame_lasti needs to be greater than 257 to prevent
+ # PyLong_FromLong() from returning cached integers, which
+ # don't require a memory allocation. Prepend some dummy code
+ # to artificially increase the instruction index.
+ warmup_code = "a = list(range(0, 1))\n" * 20
+ user_input = warmup_code + dedent("""
+ try:
+ import _testcapi
+ _testcapi.set_nomemory(0)
+ b = list(range(1000, 2000))
+ except Exception as e:
+ import traceback
+ traceback.print_exc()
+ """)
+ with SuppressCrashReport():
+ with script_helper.spawn_python('-c', user_input) as p:
+ p.wait()
+ output = p.stdout.read()
+
+ self.assertIn(p.returncode, (0, 1))
+ self.assertGreater(len(output), 0) # At minimum, should not hang
+ self.assertIn(b"MemoryError", output)
+
class NameErrorTests(unittest.TestCase):
def test_name_error_has_name(self):
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
PyObject *lasti = PyLong_FromLong(frame_lasti);
if (lasti == NULL) {
- goto exception_unwind;
+ // Instead of going back to exception_unwind (which would cause
+ // infinite recursion), directly exit to let the original exception
+ // propagate up and hopefully be handled at a higher level.
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ goto exit_unwind;
}
PUSH(lasti);
}