]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-79932: raise exception if frame.clear() is called on a suspended frame (#111792)
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Tue, 7 Nov 2023 08:49:30 +0000 (08:49 +0000)
committerGitHub <noreply@github.com>
Tue, 7 Nov 2023 08:49:30 +0000 (08:49 +0000)
Doc/reference/datamodel.rst
Doc/whatsnew/3.13.rst
Lib/test/test_frame.py
Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst [new file with mode: 0644]
Objects/frameobject.c

index 9e9fe831f4a647aded16fc47b6d93b72fcc5c9d8..f7d3d2d0bbec23a465003b86cb13e5be7d23abb1 100644 (file)
@@ -1214,10 +1214,15 @@ Frame objects support one method:
    objects (for example when catching an exception and storing its
    traceback for later use).
 
-   :exc:`RuntimeError` is raised if the frame is currently executing.
+   :exc:`RuntimeError` is raised if the frame is currently executing
+   or suspended.
 
    .. versionadded:: 3.4
 
+   .. versionchanged:: 3.13
+      Attempting to clear a suspended frame raises :exc:`RuntimeError`
+      (as has always been the case for executing frames).
+
 
 .. _traceback-objects:
 
index e12c2a1b0454fd982cae74ea4f04f937a15e4b93..ef83f662788fe4cd908bc393df5fee5e0a141b71 100644 (file)
@@ -397,6 +397,10 @@ Deprecated
   and methods that consider plural forms even if the translation was not found.
   (Contributed by Serhiy Storchaka in :gh:`88434`.)
 
+* Calling :meth:`frame.clear` on a suspended frame raises :exc:`RuntimeError`
+  (as has always been the case for an executing frame).
+  (Contributed by Irit Katriel in :gh:`79932`.)
+
 
 Pending Removal in Python 3.14
 ------------------------------
index 9491c7facdf077bdcb02189390d66193c37d5191..7f17666a8d9697b122f1fc7f70f95a1c735262ad 100644 (file)
@@ -80,9 +80,11 @@ class ClearTest(unittest.TestCase):
         gen = g()
         next(gen)
         self.assertFalse(endly)
-        # Clearing the frame closes the generator
-        gen.gi_frame.clear()
-        self.assertTrue(endly)
+
+        # Cannot clear a suspended frame
+        with self.assertRaisesRegex(RuntimeError, r'suspended frame'):
+            gen.gi_frame.clear()
+        self.assertFalse(endly)
 
     def test_clear_executing(self):
         # Attempting to clear an executing frame is forbidden.
@@ -114,9 +116,10 @@ class ClearTest(unittest.TestCase):
         gen = g()
         f = next(gen)
         self.assertFalse(endly)
-        # Clearing the frame closes the generator
-        f.clear()
-        self.assertTrue(endly)
+        # Cannot clear a suspended frame
+        with self.assertRaisesRegex(RuntimeError, 'suspended frame'):
+            f.clear()
+        self.assertFalse(endly)
 
     def test_lineno_with_tracing(self):
         def record_line():
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst
new file mode 100644 (file)
index 0000000..543dbe4
--- /dev/null
@@ -0,0 +1 @@
+Raise exception if :meth:`frame.clear` is called on a suspended frame.
index 3a10f622ccc6c79137f267a55823f6b6796a7fb2..be330a775872c2df98af4c82f9332800347d2138 100644 (file)
@@ -937,6 +937,9 @@ frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
         if (gen->gi_frame_state == FRAME_EXECUTING) {
             goto running;
         }
+        if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) {
+            goto suspended;
+        }
         _PyGen_Finalize((PyObject *)gen);
     }
     else if (f->f_frame->owner == FRAME_OWNED_BY_THREAD) {
@@ -951,6 +954,10 @@ running:
     PyErr_SetString(PyExc_RuntimeError,
                     "cannot clear an executing frame");
     return NULL;
+suspended:
+    PyErr_SetString(PyExc_RuntimeError,
+                    "cannot clear a suspended frame");
+    return NULL;
 }
 
 PyDoc_STRVAR(clear__doc__,