Skip to content

Commit a607b73

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

File tree

4 files changed

+28
-10
lines changed

4 files changed

+28
-10
lines changed

Include/internal/pycore_frame.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l
275275
/* Pushes a trampoline frame without checking for space.
276276
* Must be guarded by _PyThreadState_HasStackSpace() */
277277
static inline _PyInterpreterFrame *
278-
_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, int prev_instr)
278+
_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int prev_instr)
279279
{
280280
CALL_STAT_INC(frames_pushed);
281281
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top;
@@ -288,7 +288,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
288288
frame->f_globals = NULL;
289289
#endif
290290
frame->f_locals = NULL;
291-
frame->stacktop = code->co_nlocalsplus + stackdepth;
291+
frame->stacktop = code->co_nlocalsplus;
292292
frame->frame_obj = NULL;
293293
frame->prev_instr = _PyCode_CODE(code) + prev_instr;
294294
frame->owner = FRAME_OWNED_BY_THREAD;

Lib/test/test_class.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,24 @@ 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
743761

744762
if __name__ == '__main__':
745763
unittest.main()

Python/bytecodes.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,15 +2924,15 @@ dummy_func(
29242924
goto error;
29252925
}
29262926
Py_DECREF(tp);
2927+
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
2928+
tstate, (PyCodeObject *)&_Py_InitCleanup, 0);
2929+
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK);
29272930
if (_Py_EnterRecursivePy(tstate)) {
29282931
goto exit_unwind;
29292932
}
2930-
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
2931-
tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0);
2932-
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK);
29332933
/* Push self onto stack of shim */
29342934
Py_INCREF(self);
2935-
shim->localsplus[0] = self;
2935+
_PyFrame_StackPush(shim, self);
29362936
Py_INCREF(init);
29372937
_PyInterpreterFrame *init_frame = _PyFrame_PushUnchecked(tstate, init, oparg+1);
29382938
/* Copy self followed by args to __init__ frame */

Python/generated_cases.c.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)