]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-153881: Atomically load `dk_nentries` in `_PyObject_IsInstanceDictEmpty...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 21 Jul 2026 12:47:37 +0000 (14:47 +0200)
committerGitHub <noreply@github.com>
Tue, 21 Jul 2026 12:47:37 +0000 (18:17 +0530)
gh-153881: Atomically load `dk_nentries` in `_PyObject_IsInstanceDictEmpty` (GH-153882)
(cherry picked from commit 7ebe773160327026ba5393b27e2e2860db4d08b2)

Co-authored-by: Brij Kapadia <97006829+brijkapadia@users.noreply.github.com>
Lib/test/test_free_threading/test_dict.py
Misc/NEWS.d/next/Core_and_Builtins/2026-07-17-22-03-39.gh-issue-153881.oDa06s.rst [new file with mode: 0644]
Objects/dictobject.c

index ad23290a92ab3458f760741540e7daf102f7285c..4a812275143bc4d72361da628a659538564b292e 100644 (file)
@@ -336,5 +336,25 @@ class TestDict(TestCase):
         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 (file)
index 0000000..8facf88
--- /dev/null
@@ -0,0 +1,2 @@
+Fix potential data race when calling :meth:`~object.__getstate__`
+under the :term:`free-threaded build`.
index eebb896f5d785b25554fd1ac0a2f24e97f5508db..29b6361eea4feb4605e958e0a7a98c76fc244b9f 100644 (file)
@@ -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;
                 }