From 9cc800add0c9e5a15bd7c44171b751c180503401 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sat, 29 Oct 2022 00:38:47 +0100 Subject: [PATCH] gh-79932: do not allow to clear a suspended frame --- Lib/test/test_frame.py | 20 ++++++++++++++++++++ Objects/frameobject.c | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 4b5bb7f94ac469..8ad33fb1fc9abf 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -2,6 +2,7 @@ import re import sys import textwrap +import traceback import types import unittest import weakref @@ -111,6 +112,25 @@ def g(): f.clear() self.assertTrue(endly) + def test_clear_suspended_generator(self): + # Attempting to clear a suspended generator frame is forbidden. + def g(): + for i in range(5): + try: + 1/0 + except ZeroDivisionError as e: + yield (e, i) + + gen = g() + res = [] + for e, i in gen: + res.append(i) + with self.assertRaises(RuntimeError): + f = e.__traceback__.tb_frame + self.assertIsNotNone(f) + f.clear() + self.assertEqual(res, list(range(5))) + def test_lineno_with_tracing(self): def record_line(): f = sys._getframe(1) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index dd69207571b538..a512acf3f06273 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -949,7 +949,8 @@ frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) { if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { PyGenObject *gen = _PyFrame_GetGenerator(f->f_frame); - if (gen->gi_frame_state == FRAME_EXECUTING) { + if (gen->gi_frame_state == FRAME_EXECUTING || + gen->gi_frame_state == FRAME_SUSPENDED) { goto running; } _PyGen_Finalize((PyObject *)gen);