Skip to content

Commit 19d468a

Browse files
authored
[gh-117657] Fix some issues with TSAN in typeobject (#118249)
Fix some racing reads in typebobject.c
1 parent b2c3b70 commit 19d468a

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

Include/internal/pycore_pyatomic_ft_wrappers.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ extern "C" {
4343
_Py_atomic_load_uint8_relaxed(&value)
4444
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) \
4545
_Py_atomic_load_uint16_relaxed(&value)
46+
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) \
47+
_Py_atomic_load_uint32_relaxed(&value)
4648
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) \
4749
_Py_atomic_store_ptr_relaxed(&value, new_value)
4850
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) \
@@ -55,6 +57,9 @@ extern "C" {
5557
_Py_atomic_store_uint8_relaxed(&value, new_value)
5658
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) \
5759
_Py_atomic_store_uint16_relaxed(&value, new_value)
60+
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) \
61+
_Py_atomic_store_uint32_relaxed(&value, new_value)
62+
5863
#else
5964
#define FT_ATOMIC_LOAD_PTR(value) value
6065
#define FT_ATOMIC_STORE_PTR(value, new_value) value = new_value
@@ -69,12 +74,15 @@ extern "C" {
6974
#define FT_ATOMIC_STORE_UINT8(value, new_value) value = new_value
7075
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value
7176
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value
77+
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value
7278
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value
7379
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
7480
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value
7581
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
7682
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value
7783
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) value = new_value
84+
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) value = new_value
85+
7886
#endif
7987

8088
#ifdef __cplusplus

Objects/typeobject.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class object "PyObject *" "&PyBaseObject_Type"
4343
& ((1 << MCACHE_SIZE_EXP) - 1))
4444

4545
#define MCACHE_HASH_METHOD(type, name) \
46-
MCACHE_HASH((type)->tp_version_tag, ((Py_ssize_t)(name)) >> 3)
46+
MCACHE_HASH(FT_ATOMIC_LOAD_UINT32_RELAXED((type)->tp_version_tag), \
47+
((Py_ssize_t)(name)) >> 3)
4748
#define MCACHE_CACHEABLE_NAME(name) \
4849
PyUnicode_CheckExact(name) && \
4950
PyUnicode_IS_READY(name) && \
@@ -907,7 +908,7 @@ type_modified_unlocked(PyTypeObject *type)
907908
}
908909

909910
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
910-
type->tp_version_tag = 0; /* 0 is not a valid version tag */
911+
FT_ATOMIC_STORE_UINT32_RELAXED(type->tp_version_tag, 0); /* 0 is not a valid version tag */
911912
if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
912913
// This field *must* be invalidated if the type is modified (see the
913914
// comment on struct _specialization_cache):
@@ -984,7 +985,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
984985
clear:
985986
assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
986987
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
987-
type->tp_version_tag = 0; /* 0 is not a valid version tag */
988+
FT_ATOMIC_STORE_UINT32_RELAXED(type->tp_version_tag, 0); /* 0 is not a valid version tag */
988989
if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
989990
// This field *must* be invalidated if the type is modified (see the
990991
// comment on struct _specialization_cache):
@@ -1020,7 +1021,8 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
10201021
/* We have run out of version numbers */
10211022
return 0;
10221023
}
1023-
type->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++;
1024+
FT_ATOMIC_STORE_UINT32_RELAXED(type->tp_version_tag,
1025+
NEXT_GLOBAL_VERSION_TAG++);
10241026
assert (type->tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
10251027
}
10261028
else {
@@ -1029,7 +1031,8 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
10291031
/* We have run out of version numbers */
10301032
return 0;
10311033
}
1032-
type->tp_version_tag = NEXT_VERSION_TAG(interp)++;
1034+
FT_ATOMIC_STORE_UINT32_RELAXED(type->tp_version_tag,
1035+
NEXT_VERSION_TAG(interp)++);
10331036
assert (type->tp_version_tag != 0);
10341037
}
10351038

@@ -5085,7 +5088,9 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
50855088
// synchronize-with other writing threads by doing an acquire load on the sequence
50865089
while (1) {
50875090
int sequence = _PySeqLock_BeginRead(&entry->sequence);
5088-
if (_Py_atomic_load_uint32_relaxed(&entry->version) == type->tp_version_tag &&
5091+
uint32_t entry_version = _Py_atomic_load_uint32_relaxed(&entry->version);
5092+
uint32_t type_version = _Py_atomic_load_uint32_relaxed(&type->tp_version_tag);
5093+
if (entry_version == type_version &&
50895094
_Py_atomic_load_ptr_relaxed(&entry->name) == name) {
50905095
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
50915096
OBJECT_STAT_INC_COND(type_cache_hits, !is_dunder_name(name));

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy