Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Lib/test/test_free_threading/test_gc.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ def evil():
thread.start()
thread.join()

def test_running_method_not_collected(self):
class C:
def m(self):
wr = weakref.ref(C.__dict__["m"])
del C.m
gc.collect()
return wr() is not None

def run(self):
return self.m()

self.assertTrue(C().run())

def test_merge_brc_queue_of_detached_thread(self):
# GH-157838: objects queued for merging by a thread that is detached
# (blocked in a lock acquire, sleep, etc.) are merged and freed on its
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix a bug in the :term:`free-threaded build` where garbage collection could
prematurely collect the function object of a running method.
5 changes: 5 additions & 0 deletions Python/gc_free_threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ gc_visit_thread_stacks(PyInterpreterState *interp, struct collection_state *stat
continue;
}

gc_visit_stackref(f->f_funcobj);
gc_visit_stackref(f->f_executable);
while (top != f->localsplus) {
--top;
Expand Down Expand Up @@ -866,6 +867,10 @@ gc_visit_thread_stacks_mark_alive(PyInterpreterState *interp, gc_mark_args_t *ar
}

_PyStackRef *top = f->stackpointer;
if (gc_visit_stackref_mark_alive(args, f->f_funcobj) < 0) {
err = -1;
goto exit;
}
if (gc_visit_stackref_mark_alive(args, f->f_executable) < 0) {
err = -1;
goto exit;
Expand Down
Loading