https://github.com/python/cpython/commit/682610d700511439add24dcca62708b4c1644d3f
commit: 682610d700511439add24dcca62708b4c1644d3f
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-07-21T18:17:37+05:30
summary:

[3.15] gh-153881: Atomically load `dk_nentries` in 
`_PyObject_IsInstanceDictEmpty` (GH-153882) (#154349)

gh-153881: Atomically load `dk_nentries` in `_PyObject_IsInstanceDictEmpty` 
(GH-153882)
(cherry picked from commit 7ebe773160327026ba5393b27e2e2860db4d08b2)

Co-authored-by: Brij Kapadia <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst
M Lib/test/test_free_threading/test_dict.py
M Objects/dictobject.c

diff --git a/Lib/test/test_free_threading/test_dict.py 
b/Lib/test/test_free_threading/test_dict.py
index ad23290a92ab345..4a812275143bc4d 100644
--- a/Lib/test/test_free_threading/test_dict.py
+++ b/Lib/test/test_free_threading/test_dict.py
@@ -336,5 +336,25 @@ def reader():
         with threading_helper.start_threads([t1, t2]):
             pass
 
+    def test_getstate_race_with_shared_keys(self):
+        box = [None]
+        enter = Barrier(2)
+        leave = Barrier(2)
+
+        def reader():
+            for _ in range(1000):
+                enter.wait()
+                box[0].__getstate__()
+                leave.wait()
+
+        def writer():
+            for i in range(1000):
+                box[0] = type(f"C{i}", (), {})()
+                enter.wait()
+                setattr(box[0], str(i), 1)
+                leave.wait()
+
+        threading_helper.run_concurrently([reader, writer])
+
 if __name__ == "__main__":
     unittest.main()
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst
new file mode 100644
index 000000000000000..8facf88367fda7f
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst
@@ -0,0 +1,2 @@
+Fix potential data race when calling :meth:`~object.__getstate__`
+under the :term:`free-threaded build`.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index eebb896f5d785b2..29b6361eea4feb4 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -7654,7 +7654,7 @@ _PyObject_IsInstanceDictEmpty(PyObject *obj)
         PyDictValues *values = _PyObject_InlineValues(obj);
         if (FT_ATOMIC_LOAD_UINT8(values->valid)) {
             PyDictKeysObject *keys = CACHED_KEYS(tp);
-            for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
+            for (Py_ssize_t i = 0; i < LOAD_KEYS_NENTRIES(keys); i++) {
                 if (FT_ATOMIC_LOAD_PTR_RELAXED(values->values[i]) != NULL) {
                     return 0;
                 }

_______________________________________________
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]

Reply via email to