[3.12] gh-111058: Change coro.cr_frame/gen.gi_frame to be None for a closed coroutine/generator. (GH-112428) (#112589)

This commit is contained in:
Miss Islington (bot) 2023-12-01 15:13:15 +01:00 committed by GitHub
parent edce0c4fb3
commit 7eff607deb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 22 additions and 1 deletions

View file

@ -39,6 +39,8 @@ typedef enum _framestate {
FRAME_CLEARED = 4
} PyFrameState;
#define FRAME_STATE_FINISHED(S) ((S) >= FRAME_COMPLETED)
enum _frameowner {
FRAME_OWNED_BY_THREAD = 0,
FRAME_OWNED_BY_GENERATOR = 1,

View file

@ -2216,6 +2216,14 @@ class CoroutineTest(unittest.TestCase):
gen.cr_frame.clear()
gen.close()
def test_cr_frame_after_close(self):
async def f():
pass
gen = f()
self.assertIsNotNone(gen.cr_frame)
gen.close()
self.assertIsNone(gen.cr_frame)
def test_stack_in_coroutine_throw(self):
# Regression test for https://github.com/python/cpython/issues/93592
async def a():

View file

@ -2264,6 +2264,10 @@ class TestGetGeneratorState(unittest.TestCase):
self.generator.throw(RuntimeError)
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
def test_closed_after_close(self):
self.generator.close()
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
def test_running(self):
# As mentioned on issue #10220, checking for the RUNNING state only
# makes sense inside the generator itself.
@ -2373,6 +2377,10 @@ class TestGetCoroutineState(unittest.TestCase):
self.coroutine.throw(RuntimeError)
self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED)
def test_closed_after_close(self):
self.coroutine.close()
self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED)
def test_easy_debugging(self):
# repr() and str() of a coroutine state should contain the state name
names = 'CORO_CREATED CORO_RUNNING CORO_SUSPENDED CORO_CLOSED'.split()

View file

@ -0,0 +1,3 @@
Change coro.cr_frame/gen.gi_frame to return ``None`` after the coroutine/generator has been closed.
This fixes a bug where :func:`~inspect.getcoroutinestate` and :func:`~inspect.getgeneratorstate`
return the wrong state for a closed coroutine/generator.

View file

@ -750,7 +750,7 @@ _gen_getframe(PyGenObject *gen, const char *const name)
if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
return NULL;
}
if (gen->gi_frame_state == FRAME_CLEARED) {
if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
Py_RETURN_NONE;
}
return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((_PyInterpreterFrame *)gen->gi_iframe));