https://github.com/python/cpython/commit/8f7c4f1cefe63d15cc53e559da12ae3388aa74cd
commit: 8f7c4f1cefe63d15cc53e559da12ae3388aa74cd
branch: 3.13
author: Savannah Ostrowski <[email protected]>
committer: savannahostrowski <[email protected]>
date: 2025-12-17T20:04:53Z
summary:

[3.13] GH-100964: Fix reference cycle in exhausted generator frames (G… 
(#142904)

* [3.13] GH-100964: Fix reference cycle in exhausted generator frames 
(GH-141112)
(cherry picked from commit 92243dc62ce10715ab0d9074b23dea5a1bfa9dcc)

Co-authored-by: Savannah Ostrowski <[email protected]>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst
M Lib/test/test_generators.py
M Python/ceval.c

diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index d6014fd9d63cdf..7aa4458fc71a5e 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -112,6 +112,18 @@ def g3(): return (yield from f())
                 gen.send(2)
             self.assertEqual(cm.exception.value, 2)
 
+    def test_exhausted_generator_frame_cycle(self):
+        def g():
+            yield
+
+        generator = g()
+        frame = generator.gi_frame
+        self.assertIsNone(frame.f_back)
+        next(generator)
+        self.assertIsNone(frame.f_back)
+        next(generator, None)
+        self.assertIsNone(frame.f_back)
+
 
 class GeneratorTest(unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst b/Misc/NEWS.d/next/Core 
and Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst
new file mode 100644
index 00000000000000..7c554cf8dda5d1
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst 
@@ -0,0 +1 @@
+Fix reference cycle in exhausted generator frames. Patch by Savannah Ostrowski.
diff --git a/Python/ceval.c b/Python/ceval.c
index 0be6c57c1cf1dd..301cc3b2b90358 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1696,10 +1696,10 @@ clear_gen_frame(PyThreadState *tstate, 
_PyInterpreterFrame * frame)
     gen->gi_exc_state.previous_item = NULL;
     tstate->c_recursion_remaining--;
     assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
+    frame->previous = NULL;
     _PyFrame_ClearExceptCode(frame);
     _PyErr_ClearExcState(&gen->gi_exc_state);
     tstate->c_recursion_remaining++;
-    frame->previous = NULL;
 }
 
 void

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to