From 305cfe8cfee5207754cae738debfad07959f2c7c Mon Sep 17 00:00:00 2001
From: Brandt Bucher <brandtbucher@microsoft.com>
Date: Fri, 8 Jul 2022 18:52:26 -0700
Subject: [PATCH 1/2] [3.11] GH-93252: Fix error handling for failed Python
 calls (GH-94693) (cherry picked from commit
 8a285df806816805484fed36dce5fd5b77a215a6)

Co-authored-by: Brandt Bucher <brandtbucher@microsoft.com>
---
 Lib/test/test_call.py                                | 12 ++++++++++++
 .../2022-07-08-11-44-45.gh-issue-93252.i2358c.rst    |  2 ++
 Python/ceval.c                                       |  6 +++++-
 3 files changed, 19 insertions(+), 1 deletion(-)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst

diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py
index 6936f093e3db19..07355e8fa0616c 100644
--- a/Lib/test/test_call.py
+++ b/Lib/test/test_call.py
@@ -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):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst
new file mode 100644
index 00000000000000..1cc2d8560e53e5
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst	
@@ -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.
diff --git a/Python/ceval.c b/Python/ceval.c
index 1a5454570518ff..a24ca6fedf0380 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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;
@@ -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);

From a1ec06d67bcb6679b912de6927bb2dd6114d7c9c Mon Sep 17 00:00:00 2001
From: Christian Heimes <christian@python.org>
Date: Sat, 9 Jul 2022 13:33:23 +0200
Subject: [PATCH 2/2] Drop assert, 3.11 does not have co_framesize from
 GH-93908

---
 Python/ceval.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Python/ceval.c b/Python/ceval.c
index a24ca6fedf0380..8068889f84ff13 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -6394,8 +6394,6 @@ _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);