mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
gh-142534: Avoid TSan warnings in dictobject.c (gh-142544)
There are places we use "relaxed" loads where C11 requires "consume" or stronger. Unfortunately, compilers don't really implement "consume" so fake it for our use in a way that avoids upsetting TSan.
This commit is contained in:
parent
9fe6e3ed36
commit
0a62f8277e
3 changed files with 20 additions and 6 deletions
|
|
@ -591,6 +591,17 @@ static inline void _Py_atomic_fence_release(void);
|
|||
|
||||
// --- aliases ---------------------------------------------------------------
|
||||
|
||||
// Compilers don't really support "consume" semantics, so we fake it. Use
|
||||
// "acquire" with TSan to support false positives. Use "relaxed" otherwise,
|
||||
// because CPUs on all platforms we support respect address dependencies without
|
||||
// extra barriers.
|
||||
// See 2.6.7 in https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2055r0.pdf
|
||||
#if defined(_Py_THREAD_SANITIZER)
|
||||
# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_acquire
|
||||
#else
|
||||
# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_relaxed
|
||||
#endif
|
||||
|
||||
#if SIZEOF_LONG == 8
|
||||
# define _Py_atomic_load_ulong(p) \
|
||||
_Py_atomic_load_uint64((uint64_t *)p)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ extern "C" {
|
|||
_Py_atomic_store_ptr(&value, new_value)
|
||||
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) \
|
||||
_Py_atomic_load_ptr_acquire(&value)
|
||||
#define FT_ATOMIC_LOAD_PTR_CONSUME(value) \
|
||||
_Py_atomic_load_ptr_consume(&value)
|
||||
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) \
|
||||
_Py_atomic_load_uintptr_acquire(&value)
|
||||
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) \
|
||||
|
|
@ -125,6 +127,7 @@ extern "C" {
|
|||
#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) value
|
||||
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) value
|
||||
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) value
|
||||
#define FT_ATOMIC_LOAD_PTR_CONSUME(value) value
|
||||
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) value
|
||||
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) value
|
||||
#define FT_ATOMIC_LOAD_UINT8(value) value
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,7 @@ compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
|
|||
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
|
||||
PyObject *ep_key = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key);
|
||||
PyObject *ep_key = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_key);
|
||||
assert(ep_key != NULL);
|
||||
assert(PyUnicode_CheckExact(ep_key));
|
||||
if (ep_key == key ||
|
||||
|
|
@ -1371,7 +1371,7 @@ compare_unicode_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
|
|||
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
|
||||
PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
|
||||
PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key);
|
||||
assert(startkey == NULL || PyUnicode_CheckExact(ep->me_key));
|
||||
assert(!PyUnicode_CheckExact(key));
|
||||
|
||||
|
|
@ -1414,7 +1414,7 @@ compare_unicode_unicode_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
|
|||
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
|
||||
PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
|
||||
PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key);
|
||||
if (startkey == key) {
|
||||
assert(PyUnicode_CheckExact(startkey));
|
||||
return 1;
|
||||
|
|
@ -1450,7 +1450,7 @@ compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
|
|||
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
|
||||
PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
|
||||
PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key);
|
||||
if (startkey == key) {
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -5526,7 +5526,7 @@ dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
|
|||
k = _Py_atomic_load_ptr_acquire(&d->ma_keys);
|
||||
assert(i >= 0);
|
||||
if (_PyDict_HasSplitTable(d)) {
|
||||
PyDictValues *values = _Py_atomic_load_ptr_relaxed(&d->ma_values);
|
||||
PyDictValues *values = _Py_atomic_load_ptr_consume(&d->ma_values);
|
||||
if (values == NULL) {
|
||||
goto concurrent_modification;
|
||||
}
|
||||
|
|
@ -7114,7 +7114,7 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
|
|||
Py_BEGIN_CRITICAL_SECTION(dict);
|
||||
|
||||
if (dict->ma_values == values && FT_ATOMIC_LOAD_UINT8(values->valid)) {
|
||||
value = _Py_atomic_load_ptr_relaxed(&values->values[ix]);
|
||||
value = _Py_atomic_load_ptr_consume(&values->values[ix]);
|
||||
*attr = _Py_XNewRefWithLock(value);
|
||||
success = true;
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue