Skip to content

Commit 8ee9793

Browse files
committed
Make sure that frame stack is in valid state should a recursion error happen when calling a class.
1 parent e8e59ee commit 8ee9793

File tree

3 files changed

+102
-81
lines changed

3 files changed

+102
-81
lines changed

Lib/test/test_class.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,25 @@ 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+
try:
749+
C()
750+
except RecursionError:
751+
# OK
752+
pass
753+
def add_one_level():
754+
#Each call to C() consumes 2 levels, so offset by 1.
755+
C()
756+
try:
757+
add_one_level()
758+
except RecursionError:
759+
# OK
760+
pass
761+
743762

744763
if __name__ == '__main__':
745764
unittest.main()

Python/bytecodes.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,9 +2924,6 @@ dummy_func(
29242924
goto error;
29252925
}
29262926
Py_DECREF(tp);
2927-
if (_Py_EnterRecursivePy(tstate)) {
2928-
goto exit_unwind;
2929-
}
29302927
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
29312928
tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0);
29322929
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK);
@@ -2950,6 +2947,10 @@ dummy_func(
29502947
shim->previous = frame;
29512948
frame = cframe.current_frame = init_frame;
29522949
CALL_STAT_INC(inlined_py_calls);
2950+
/* Account for pushing the extra frame.
2951+
* We don't check recursion depth here,
2952+
* as it will be checked after start_frame */
2953+
tstate->py_recursion_remaining--;
29532954
goto start_frame;
29542955
}
29552956

0 commit comments

Comments
 (0)