From 9e687600cc73d7c4ec4df59b399bb1b245182854 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 17 Dec 2025 11:21:45 -0800 Subject: [PATCH 1/2] [3.13] GH-100964: Fix reference cycle in exhausted generator frames (GH-141112) (cherry picked from commit 92243dc62ce10715ab0d9074b23dea5a1bfa9dcc) Co-authored-by: Savannah Ostrowski --- Lib/test/test_generators.py | 12 ++++++++++++ .../2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst | 1 + Python/ceval.c | 3 +-- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst 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..1f309226136174 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1696,10 +1696,9 @@ 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 From 89fb267f3b459f02182593a6d0519e9158f3e6d5 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Wed, 17 Dec 2025 11:40:39 -0800 Subject: [PATCH 2/2] Add back missed line --- Python/ceval.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/ceval.c b/Python/ceval.c index 1f309226136174..301cc3b2b90358 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1699,6 +1699,7 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) frame->previous = NULL; _PyFrame_ClearExceptCode(frame); _PyErr_ClearExcState(&gen->gi_exc_state); + tstate->c_recursion_remaining++; } void