https://github.com/python/cpython/commit/12af26d17e4343c1f4ea3a1019bcc34ee76671c3
commit: 12af26d17e4343c1f4ea3a1019bcc34ee76671c3
branch: main
author: Edward Xu <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-06-06T17:03:04Z
summary:
gh-150411: fix `gc_generation.count` race in free-threading (#150413)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst
M Lib/test/test_free_threading/test_gc.py
M Modules/gcmodule.c
diff --git a/Lib/test/test_free_threading/test_gc.py
b/Lib/test/test_free_threading/test_gc.py
index cc1888dae48bc0..39901023450940 100644
--- a/Lib/test/test_free_threading/test_gc.py
+++ b/Lib/test/test_free_threading/test_gc.py
@@ -124,6 +124,35 @@ def setter():
finally:
gc.set_threshold(*current_threshold)
+ def test_get_count(self):
+ class CyclicReference:
+ def __init__(self):
+ self.ref = self
+
+ NUM_ALLOCATORS = 7
+ NUM_READERS = 1
+ NUM_THREADS = NUM_ALLOCATORS + NUM_READERS
+ NUM_ITERS = 1000
+
+ barrier = threading.Barrier(NUM_THREADS)
+
+ def allocator():
+ barrier.wait()
+ for _ in range(NUM_ITERS):
+ CyclicReference()
+
+
+ def reader():
+ barrier.wait()
+ for _ in range(NUM_ITERS):
+ gc.get_count()
+
+ threads = [Thread(target=allocator) for _ in range(NUM_ALLOCATORS)]
+ threads.extend(Thread(target=reader) for _ in range(NUM_READERS))
+
+ with threading_helper.start_threads(threads):
+ pass
+
if __name__ == "__main__":
unittest.main()
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst
new file mode 100644
index 00000000000000..5b19a4fff5ddc7
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-26-00-06-30.gh-issue-150411.u-d-_5.rst
@@ -0,0 +1,2 @@
+Fix a data race in the free-threaded build when :func:`gc.get_count` reads
+the young generation allocation count while another thread updates it.
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 8762e592b25810..0093995441e390 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -233,7 +233,7 @@ gc_get_count_impl(PyObject *module)
gcstate->generations[2].count);
#else
return Py_BuildValue("(iii)",
- gcstate->young.count,
+ _Py_atomic_load_int_relaxed(&gcstate->young.count),
gcstate->old[0].count,
gcstate->old[1].count);
#endif
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]