gh-129824: fix data races in subinterpreters under TSAN (#135794) · python/cpython@b582d75 · GitHub | Latest TMZ Celebrity News & Gossip | Watch TMZ Live
Skip to content

Commit b582d75

Browse files
gh-129824: fix data races in subinterpreters under TSAN (#135794)
This fixes the data races in typeobject.c in subinterpreters under free-threading. The type flags and slots are only modified in the main interpreter as all static types are first initialised in main interpreter.
1 parent 85f092f commit b582d75

File tree

1 file changed

+44
-17
lines changed

1 file changed

+44
-17
lines changed

Objects/typeobject.c

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ class object "PyObject *" "&PyBaseObject_Type"
5454
PyUnicode_CheckExact(name) && \
5555
(PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
5656

57-
#define NEXT_GLOBAL_VERSION_TAG _PyRuntime.types.next_version_tag
5857
#define NEXT_VERSION_TAG(interp) \
5958
(interp)->types.next_version_tag
6059

@@ -266,8 +265,8 @@ static_ext_type_lookup(PyInterpreterState *interp, size_t index,
266265
assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES);
267266

268267
size_t full_index = index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES;
269-
int64_t interp_count =
270-
_PyRuntime.types.managed_static.types[full_index].interp_count;
268+
int64_t interp_count = _Py_atomic_load_int64(
269+
&_PyRuntime.types.managed_static.types[full_index].interp_count);
271270
assert((interp_count == 0) ==
272271
(_PyRuntime.types.managed_static.types[full_index].type == NULL));
273272
*p_interp_count = interp_count;
@@ -344,7 +343,7 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self,
344343
: index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES;
345344

346345
assert((initial == 1) ==
347-
(_PyRuntime.types.managed_static.types[full_index].interp_count == 0));
346+
(_Py_atomic_load_int64(&_PyRuntime.types.managed_static.types[full_index].interp_count) == 0));
348347
(void)_Py_atomic_add_int64(
349348
&_PyRuntime.types.managed_static.types[full_index].interp_count, 1);
350349

@@ -393,7 +392,7 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self,
393392
: &(interp->types.for_extensions.initialized[index]);
394393
assert(state != NULL);
395394

396-
assert(_PyRuntime.types.managed_static.types[full_index].interp_count > 0);
395+
assert(_Py_atomic_load_int64(&_PyRuntime.types.managed_static.types[full_index].interp_count) > 0);
397396
assert(_PyRuntime.types.managed_static.types[full_index].type == state->type);
398397

399398
assert(state->type != NULL);
@@ -403,7 +402,7 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self,
403402
(void)_Py_atomic_add_int64(
404403
&_PyRuntime.types.managed_static.types[full_index].interp_count, -1);
405404
if (final) {
406-
assert(!_PyRuntime.types.managed_static.types[full_index].interp_count);
405+
assert(!_Py_atomic_load_int64(&_PyRuntime.types.managed_static.types[full_index].interp_count));
407406
_PyRuntime.types.managed_static.types[full_index].type = NULL;
408407

409408
managed_static_type_index_clear(self);
@@ -1359,6 +1358,19 @@ _PyType_LookupByVersion(unsigned int version)
13591358
#error "_Py_ATTR_CACHE_UNUSED must be bigger than max"
13601359
#endif
13611360

1361+
static inline unsigned int
1362+
next_global_version_tag(void)
1363+
{
1364+
unsigned int old;
1365+
do {
1366+
old = _Py_atomic_load_uint_relaxed(&_PyRuntime.types.next_version_tag);
1367+
if (old >= _Py_MAX_GLOBAL_TYPE_VERSION_TAG) {
1368+
return 0;
1369+
}
1370+
} while (!_Py_atomic_compare_exchange_uint(&_PyRuntime.types.next_version_tag, &old, old + 1));
1371+
return old + 1;
1372+
}
1373+
13621374
static int
13631375
assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
13641376
{
@@ -1389,11 +1401,12 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
13891401
}
13901402
if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
13911403
/* static types */
1392-
if (NEXT_GLOBAL_VERSION_TAG > _Py_MAX_GLOBAL_TYPE_VERSION_TAG) {
1404+
unsigned int next_version_tag = next_global_version_tag();
1405+
if (next_version_tag == 0) {
13931406
/* We have run out of version numbers */
13941407
return 0;
13951408
}
1396-
set_version_unlocked(type, NEXT_GLOBAL_VERSION_TAG++);
1409+
set_version_unlocked(type, next_version_tag);
13971410
assert (type->tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
13981411
}
13991412
else {
@@ -9007,7 +9020,11 @@ type_ready_set_new(PyTypeObject *type, int initial)
90079020
&& base == &PyBaseObject_Type
90089021
&& !(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
90099022
{
9010-
type_add_flags(type, Py_TPFLAGS_DISALLOW_INSTANTIATION);
9023+
if (initial) {
9024+
type_add_flags(type, Py_TPFLAGS_DISALLOW_INSTANTIATION);
9025+
} else {
9026+
assert(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION);
9027+
}
90119028
}
90129029

90139030
if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
@@ -9021,13 +9038,17 @@ type_ready_set_new(PyTypeObject *type, int initial)
90219038
}
90229039
}
90239040
else {
9024-
// tp_new is NULL: inherit tp_new from base
9025-
type->tp_new = base->tp_new;
9041+
if (initial) {
9042+
// tp_new is NULL: inherit tp_new from base
9043+
type->tp_new = base->tp_new;
9044+
}
90269045
}
90279046
}
90289047
else {
90299048
// Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL
9030-
type->tp_new = NULL;
9049+
if (initial) {
9050+
type->tp_new = NULL;
9051+
}
90319052
}
90329053
return 0;
90339054
}
@@ -9160,7 +9181,12 @@ type_ready(PyTypeObject *type, int initial)
91609181
}
91619182

91629183
/* All done -- set the ready flag */
9163-
type_add_flags(type, Py_TPFLAGS_READY);
9184+
if (initial) {
9185+
type_add_flags(type, Py_TPFLAGS_READY);
9186+
} else {
9187+
assert(type->tp_flags & Py_TPFLAGS_READY);
9188+
}
9189+
91649190
stop_readying(type);
91659191

91669192
assert(_PyType_CheckConsistency(type));
@@ -9209,15 +9235,16 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self,
92099235
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT));
92109236
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF));
92119237

9212-
if ((self->tp_flags & Py_TPFLAGS_READY) == 0) {
9213-
assert(initial);
9238+
if (initial) {
9239+
assert((self->tp_flags & Py_TPFLAGS_READY) == 0);
92149240

92159241
type_add_flags(self, _Py_TPFLAGS_STATIC_BUILTIN);
92169242
type_add_flags(self, Py_TPFLAGS_IMMUTABLETYPE);
92179243

9218-
assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
92199244
if (self->tp_version_tag == 0) {
9220-
_PyType_SetVersion(self, NEXT_GLOBAL_VERSION_TAG++);
9245+
unsigned int next_version_tag = next_global_version_tag();
9246+
assert(next_version_tag != 0);
9247+
_PyType_SetVersion(self, next_version_tag);
92219248
}
92229249
}
92239250
else {

0 commit comments

Comments
 (0)

TMZ Celebrity News – Breaking Stories, Videos & Gossip

Looking for the latest TMZ celebrity news? You've come to the right place. From shocking Hollywood scandals to exclusive videos, TMZ delivers it all in real time.

Whether it’s a red carpet slip-up, a viral paparazzi moment, or a legal drama involving your favorite stars, TMZ news is always first to break the story. Stay in the loop with daily updates, insider tips, and jaw-dropping photos.

🎥 Watch TMZ Live

TMZ Live brings you daily celebrity news and interviews straight from the TMZ newsroom. Don’t miss a beat—watch now and see what’s trending in Hollywood.