Skip to content

Commit 24fb627

Browse files
authored
GH-106057: Handle recursion errors in inline class calls properly. (GH-106108)
1 parent e1d45b8 commit 24fb627

File tree

4 files changed

+108
-91
lines changed

4 files changed

+108
-91
lines changed

Lib/test/test_class.py

+15
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,21 @@ class A(0, 1, 2, 3, 4, 5, 6, 7, **d): pass
740740
class A(0, *range(1, 8), **d, foo='bar'): pass
741741
self.assertEqual(A, (tuple(range(8)), {'foo': 'bar'}))
742742

743+
def testClassCallRecursionLimit(self):
744+
class C:
745+
def __init__(self):
746+
self.c = C()
747+
748+
with self.assertRaises(RecursionError):
749+
C()
750+
751+
def add_one_level():
752+
#Each call to C() consumes 2 levels, so offset by 1.
753+
C()
754+
755+
with self.assertRaises(RecursionError):
756+
add_one_level()
757+
743758

744759
if __name__ == '__main__':
745760
unittest.main()

Python/bytecodes.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -2985,9 +2985,6 @@ dummy_func(
29852985
goto error;
29862986
}
29872987
Py_DECREF(tp);
2988-
if (_Py_EnterRecursivePy(tstate)) {
2989-
goto exit_unwind;
2990-
}
29912988
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
29922989
tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0);
29932990
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK);
@@ -3011,6 +3008,10 @@ dummy_func(
30113008
shim->previous = frame;
30123009
frame = cframe.current_frame = init_frame;
30133010
CALL_STAT_INC(inlined_py_calls);
3011+
/* Account for pushing the extra frame.
3012+
* We don't check recursion depth here,
3013+
* as it will be checked after start_frame */
3014+
tstate->py_recursion_remaining--;
30143015
goto start_frame;
30153016
}
30163017

Python/executor_cases.c.h

+10-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)