summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-09-14 02:02:27 (GMT)
committerGitHub <noreply@github.com>2024-09-14 02:02:27 (GMT)
commitb02301fa5a543266ee310a6d98278d2b8e26d7b3 (patch)
treec6e24188036f33d57f09ca183c3d02eb8f64cb82 /Python
parent38809171b8768517824fb62d48abe2cb0aff8429 (diff)
downloadcpython-b02301fa5a543266ee310a6d98278d2b8e26d7b3.zip
cpython-b02301fa5a543266ee310a6d98278d2b8e26d7b3.tar.gz
cpython-b02301fa5a543266ee310a6d98278d2b8e26d7b3.tar.bz2
gh-124068: Fix reference leak with generators in the free-threaded build (#124069)
If the generator is already cleared, then most fields in the generator's frame are not valid other than f_executable. The invalid fields may contain dangling pointers and should not be used.
Diffstat (limited to 'Python')
-rw-r--r--Python/gc_free_threading.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c
index e981f87..c645f1b 100644
--- a/Python/gc_free_threading.c
+++ b/Python/gc_free_threading.c
@@ -186,7 +186,20 @@ frame_disable_deferred_refcounting(_PyInterpreterFrame *frame)
// Convert locals, variables, and the executable object to strong
// references from (possibly) deferred references.
assert(frame->stackpointer != NULL);
+ assert(frame->owner == FRAME_OWNED_BY_FRAME_OBJECT ||
+ frame->owner == FRAME_OWNED_BY_GENERATOR);
+
frame->f_executable = PyStackRef_AsStrongReference(frame->f_executable);
+
+ if (frame->owner == FRAME_OWNED_BY_GENERATOR) {
+ PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
+ if (gen->gi_frame_state == FRAME_CLEARED) {
+ // gh-124068: if the generator is cleared, then most fields other
+ // than f_executable are not valid.
+ return;
+ }
+ }
+
for (_PyStackRef *ref = frame->localsplus; ref < frame->stackpointer; ref++) {
if (!PyStackRef_IsNull(*ref) && PyStackRef_IsDeferred(*ref)) {
*ref = PyStackRef_AsStrongReference(*ref);