Skip to content

Commit

Permalink
pythonGH-93252: Fix error handling for failed Python calls (pythonGH-…
Browse files Browse the repository at this point in the history
…94693)

(cherry picked from commit 8a285df)

Co-authored-by: Brandt Bucher <[email protected]>
  • Loading branch information
brandtbucher authored and miss-islington committed Jul 9, 2022
1 parent cb4359c commit 23d96a6
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 1 deletion.
12 changes: 12 additions & 0 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ def fn(**kw):
self.assertIsInstance(res, dict)
self.assertEqual(list(res.items()), expected)

def test_frames_are_popped_after_failed_calls(self):
# GH-93252: stuff blows up if we don't pop the new frame after
# recovering from failed calls:
def f():
pass
for _ in range(1000):
try:
f(None)
except TypeError:
pass
# BOOM!


@cpython_only
class CFunctionCallsErrorMessages(unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix an issue that caused internal frames to outlive failed Python function
calls, possibly resulting in memory leaks or hard interpreter crashes.
6 changes: 5 additions & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -6370,7 +6370,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
}
if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
assert(frame->owner != FRAME_OWNED_BY_GENERATOR);
_PyFrame_Clear(frame);
_PyEvalFrameClearAndPop(tstate, frame);
return NULL;
}
return frame;
Expand All @@ -6392,6 +6392,10 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
static void
_PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
{
// Make sure that this is, indeed, the top frame. We can't check this in
// _PyThreadState_PopFrame, since f_code is already cleared at that point:
assert((PyObject **)frame + frame->f_code->co_framesize ==
tstate->datastack_top);
tstate->recursion_remaining--;
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
assert(frame->owner == FRAME_OWNED_BY_THREAD);
Expand Down

0 comments on commit 23d96a6

Please sign in to comment.