Skip to content

Commit 5da0280

Browse files
authored
gh-117657: Fixes a few small TSAN issues in dictobject (#118200)
Fixup TSAN errors for dict
1 parent cce5ae6 commit 5da0280

File tree

4 files changed

+19
-15
lines changed

4 files changed

+19
-15
lines changed

Include/cpython/dictobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ static inline Py_ssize_t PyDict_GET_SIZE(PyObject *op) {
5656
PyDictObject *mp;
5757
assert(PyDict_Check(op));
5858
mp = _Py_CAST(PyDictObject*, op);
59+
#ifdef Py_GIL_DISABLED
60+
return _Py_atomic_load_ssize_relaxed(&mp->ma_used);
61+
#else
5962
return mp->ma_used;
63+
#endif
6064
}
6165
#define PyDict_GET_SIZE(op) PyDict_GET_SIZE(_PyObject_CAST(op))
6266

Include/internal/pycore_object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ static inline PyDictObject *
688688
_PyObject_GetManagedDict(PyObject *obj)
689689
{
690690
PyManagedDictPointer *dorv = _PyObject_ManagedDictPointer(obj);
691-
return (PyDictObject *)FT_ATOMIC_LOAD_PTR_RELAXED(dorv->dict);
691+
return (PyDictObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(dorv->dict);
692692
}
693693

694694
static inline PyDictValues *

Objects/dictobject.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,10 +1097,11 @@ compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
10971097
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
10981098
{
10991099
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1100-
assert(ep->me_key != NULL);
1101-
assert(PyUnicode_CheckExact(ep->me_key));
1102-
if (ep->me_key == key ||
1103-
(unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
1100+
PyObject *ep_key = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key);
1101+
assert(ep_key != NULL);
1102+
assert(PyUnicode_CheckExact(ep_key));
1103+
if (ep_key == key ||
1104+
(unicode_get_hash(ep_key) == hash && unicode_eq(ep_key, key))) {
11041105
return 1;
11051106
}
11061107
return 0;
@@ -1761,10 +1762,12 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
17611762
else {
17621763
assert(old_value != NULL);
17631764
if (DK_IS_UNICODE(mp->ma_keys)) {
1764-
DK_UNICODE_ENTRIES(mp->ma_keys)[ix].me_value = value;
1765+
PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
1766+
STORE_VALUE(ep, value);
17651767
}
17661768
else {
1767-
DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
1769+
PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
1770+
STORE_VALUE(ep, value);
17681771
}
17691772
}
17701773
mp->ma_version_tag = new_version;
@@ -1810,15 +1813,15 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
18101813
if (unicode) {
18111814
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(newkeys);
18121815
ep->me_key = key;
1813-
ep->me_value = value;
1816+
STORE_VALUE(ep, value);
18141817
}
18151818
else {
18161819
PyDictKeyEntry *ep = DK_ENTRIES(newkeys);
18171820
ep->me_key = key;
18181821
ep->me_hash = hash;
1819-
ep->me_value = value;
1822+
STORE_VALUE(ep, value);
18201823
}
1821-
mp->ma_used++;
1824+
FT_ATOMIC_STORE_SSIZE_RELAXED(mp->ma_used, FT_ATOMIC_LOAD_SSIZE_RELAXED(mp->ma_used) + 1);
18221825
mp->ma_version_tag = new_version;
18231826
newkeys->dk_usable--;
18241827
newkeys->dk_nentries++;
@@ -2510,7 +2513,7 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
25102513
Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix);
25112514
assert(hashpos >= 0);
25122515

2513-
mp->ma_used--;
2516+
FT_ATOMIC_STORE_SSIZE_RELAXED(mp->ma_used, FT_ATOMIC_LOAD_SSIZE(mp->ma_used) - 1);
25142517
mp->ma_version_tag = new_version;
25152518
if (_PyDict_HasSplitTable(mp)) {
25162519
assert(old_value == mp->ma_values->values[ix]);
@@ -6895,7 +6898,7 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
68956898
}
68966899

68976900
#ifdef Py_GIL_DISABLED
6898-
PyObject *value = _Py_atomic_load_ptr_relaxed(&values->values[ix]);
6901+
PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]);
68996902
if (value == NULL || _Py_TryIncrefCompare(&values->values[ix], value)) {
69006903
*attr = value;
69016904
return true;

Tools/tsan/suppressions_free_threading.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ race:_PyObject_GC_TRACK
2828
race:_PyParkingLot_Park
2929
race:_PyType_HasFeature
3030
race:assign_version_tag
31-
race:compare_unicode_unicode
32-
race:delitem_common
33-
race:dictresize
3431
race:gc_collect_main
3532
race:gc_restore_tid
3633
race:initialize_new_array

0 commit comments

Comments
 (0)