https://github.com/python/cpython/commit/169285470630b697c5e6e0e4c8091c31f25ffb04
commit: 169285470630b697c5e6e0e4c8091c31f25ffb04
branch: main
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-05-18T21:39:45+05:30
summary:
gh-149816: fix `dict.clear()` race on split-table dict with non-embedded values
(#149914)
files:
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 55272a00c3ad501..dfe0634211d4b02 100644
--- a/Lib/test/test_free_threading/test_dict.py
+++ b/Lib/test/test_free_threading/test_dict.py
@@ -268,6 +268,34 @@ def watcher():
finally:
_testcapi.clear_dict_watcher(wid)
+ def test_racing_split_dict_clear_and_lookup(self):
+ class C:
+ pass
+
+ keys = [f"a{i}" for i in range(16)]
+
+ def make_split_nonembedded():
+ inst = C()
+ for key in keys:
+ setattr(inst, key, keys.index(key))
+ # dict.copy() of a split instance dict yields a split table
+ # with non-embedded values
+ return inst.__dict__.copy()
+
+ d = make_split_nonembedded()
+
+ def clearer():
+ for _ in range(1000):
+ d.clear()
+ d.update(make_split_nonembedded())
+
+ def reader():
+ for _ in range(1000):
+ for k in keys:
+ d.get(k)
+
+ threading_helper.run_concurrently([clearer, reader, reader])
+
def test_racing_dict_update_and_method_lookup(self):
# gh-144295: test race between dict modifications and method lookups.
# Uses BytesIO because the race requires a type without
Py_TPFLAGS_INLINE_VALUES
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index b33a273dac3b95b..a7d67812bec9250 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -3083,10 +3083,12 @@ clear_lock_held(PyObject *op)
set_keys(mp, Py_EMPTY_KEYS);
n = oldkeys->dk_nentries;
for (i = 0; i < n; i++) {
- Py_CLEAR(oldvalues->values[i]);
+ PyObject *tmp = oldvalues->values[i];
+ FT_ATOMIC_STORE_PTR_RELEASE(oldvalues->values[i], NULL);
+ Py_XDECREF(tmp);
}
free_values(oldvalues, IS_DICT_SHARED(mp));
- dictkeys_decref(oldkeys, false);
+ dictkeys_decref(oldkeys, IS_DICT_SHARED(mp));
}
ASSERT_CONSISTENT(mp);
}
_______________________________________________
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]