Skip to content

Commit bcc829e

Browse files
fix data races in typeobject.c
1 parent b14986c commit bcc829e

File tree

1 file changed

+36
-12
lines changed

1 file changed

+36
-12
lines changed

Objects/typeobject.c

Lines changed: 36 additions & 12 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

@@ -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+
get_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 (unsigned int)-1;
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 = get_next_global_version_tag();
1405+
if (next_version_tag == (unsigned int)-1) {
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 {
@@ -9005,7 +9018,7 @@ type_ready_set_new(PyTypeObject *type, int initial)
90059018
default also inherit object.__new__. */
90069019
if (type->tp_new == NULL
90079020
&& base == &PyBaseObject_Type
9008-
&& !(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
9021+
&& !(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && initial)
90099022
{
90109023
type_add_flags(type, Py_TPFLAGS_DISALLOW_INSTANTIATION);
90119024
}
@@ -9021,13 +9034,21 @@ type_ready_set_new(PyTypeObject *type, int initial)
90219034
}
90229035
}
90239036
else {
9024-
// tp_new is NULL: inherit tp_new from base
9025-
type->tp_new = base->tp_new;
9037+
if (initial) {
9038+
// tp_new is NULL: inherit tp_new from base
9039+
type->tp_new = base->tp_new;
9040+
} else {
9041+
assert(type->tp_new = base->tp_new);
9042+
}
90269043
}
90279044
}
90289045
else {
90299046
// Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL
9030-
type->tp_new = NULL;
9047+
if (initial) {
9048+
type->tp_new = NULL;
9049+
} else {
9050+
assert(type->tp_new == NULL);
9051+
}
90319052
}
90329053
return 0;
90339054
}
@@ -9160,7 +9181,9 @@ 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+
}
91649187
stop_readying(type);
91659188

91669189
assert(_PyType_CheckConsistency(type));
@@ -9209,15 +9232,16 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self,
92099232
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT));
92109233
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF));
92119234

9212-
if ((self->tp_flags & Py_TPFLAGS_READY) == 0) {
9213-
assert(initial);
9235+
if (initial) {
9236+
assert((self->tp_flags & Py_TPFLAGS_READY) == 0);
92149237

92159238
type_add_flags(self, _Py_TPFLAGS_STATIC_BUILTIN);
92169239
type_add_flags(self, Py_TPFLAGS_IMMUTABLETYPE);
92179240

9218-
assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
92199241
if (self->tp_version_tag == 0) {
9220-
_PyType_SetVersion(self, NEXT_GLOBAL_VERSION_TAG++);
9242+
unsigned int next_version_tag = get_next_global_version_tag();
9243+
assert(next_version_tag != (unsigned int)-1);
9244+
_PyType_SetVersion(self, next_version_tag);
92219245
}
92229246
}
92239247
else {

0 commit comments

Comments
 (0)