[Python-checkins] GH-100964: Break cycles involving exception state when returning from generator (GH-107563)
markshannon
webhook-mailer at python.org
Wed Aug 2 13:44:24 EDT 2023
https://github.com/python/cpython/commit/0d30a5a40968cce19750be78154232fae25d641f
commit: 0d30a5a40968cce19750be78154232fae25d641f
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2023-08-02T18:44:20+01:00
summary:
GH-100964: Break cycles involving exception state when returning from generator (GH-107563)
files:
A Misc/NEWS.d/next/Core and Builtins/2023-07-30-18-05-11.gh-issue-100964.HluhBJ.rst
M Objects/genobject.c
M Python/ceval.c
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-30-18-05-11.gh-issue-100964.HluhBJ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-30-18-05-11.gh-issue-100964.HluhBJ.rst
new file mode 100644
index 0000000000000..99ebc926e2ce2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-30-18-05-11.gh-issue-100964.HluhBJ.rst
@@ -0,0 +1,2 @@
+Clear generators' exception state after ``return`` to break reference
+cycles.
diff --git a/Objects/genobject.c b/Objects/genobject.c
index a630f84fb5a29..65782be182cd7 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -149,14 +149,16 @@ gen_dealloc(PyGenObject *gen)
gen->gi_frame_state = FRAME_CLEARED;
frame->previous = NULL;
_PyFrame_ClearExceptCode(frame);
+ _PyErr_ClearExcState(&gen->gi_exc_state);
}
+ assert(gen->gi_exc_state.exc_value == NULL);
if (_PyGen_GetCode(gen)->co_flags & CO_COROUTINE) {
Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer);
}
Py_DECREF(_PyGen_GetCode(gen));
Py_CLEAR(gen->gi_name);
Py_CLEAR(gen->gi_qualname);
- _PyErr_ClearExcState(&gen->gi_exc_state);
+
PyObject_GC_Del(gen);
}
@@ -252,10 +254,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
!PyErr_ExceptionMatches(PyExc_StopAsyncIteration));
}
- /* generator can't be rerun, so release the frame */
- /* first clean reference cycle through stored exception traceback */
- _PyErr_ClearExcState(&gen->gi_exc_state);
-
+ assert(gen->gi_exc_state.exc_value == NULL);
assert(gen->gi_frame_state == FRAME_CLEARED);
*presult = result;
return result ? PYGEN_RETURN : PYGEN_ERROR;
diff --git a/Python/ceval.c b/Python/ceval.c
index 17818a0d3c17e..369b9a69152a5 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1466,6 +1466,7 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
tstate->c_recursion_remaining--;
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
_PyFrame_ClearExceptCode(frame);
+ _PyErr_ClearExcState(&gen->gi_exc_state);
tstate->c_recursion_remaining++;
frame->previous = NULL;
}
More information about the Python-checkins
mailing list