gh-79932: raise exception if frame.clear() is called on a suspended frame (#111792)

This commit is contained in:
Irit Katriel 2023-11-07 08:49:30 +00:00 committed by GitHub
parent d2ddfccfb4
commit 13405ecffd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 7 deletions

View 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:

View 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
------------------------------

View 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():

View File

@ -0,0 +1 @@
Raise exception if :meth:`frame.clear` is called on a suspended frame.

View 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__,