From bcc829ea387469258c21ad8c60ef72a0132f74ea Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 21 Jun 2025 22:34:27 +0530 Subject: [PATCH 1/4] fix data races in typeobject.c --- Objects/typeobject.c | 48 +++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b9d549610693c1..dd78fe3b6cfd60 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -54,7 +54,6 @@ class object "PyObject *" "&PyBaseObject_Type" PyUnicode_CheckExact(name) && \ (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE) -#define NEXT_GLOBAL_VERSION_TAG _PyRuntime.types.next_version_tag #define NEXT_VERSION_TAG(interp) \ (interp)->types.next_version_tag @@ -1359,6 +1358,19 @@ _PyType_LookupByVersion(unsigned int version) #error "_Py_ATTR_CACHE_UNUSED must be bigger than max" #endif +static inline unsigned int +get_next_global_version_tag(void) +{ + unsigned int old; + do { + old = _Py_atomic_load_uint_relaxed(&_PyRuntime.types.next_version_tag); + if (old >= _Py_MAX_GLOBAL_TYPE_VERSION_TAG) { + return (unsigned int)-1; + } + } while (!_Py_atomic_compare_exchange_uint(&_PyRuntime.types.next_version_tag, &old, old + 1)); + return old + 1; +} + static int assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) { @@ -1389,11 +1401,12 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) } if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { /* static types */ - if (NEXT_GLOBAL_VERSION_TAG > _Py_MAX_GLOBAL_TYPE_VERSION_TAG) { + unsigned int next_version_tag = get_next_global_version_tag(); + if (next_version_tag == (unsigned int)-1) { /* We have run out of version numbers */ return 0; } - set_version_unlocked(type, NEXT_GLOBAL_VERSION_TAG++); + set_version_unlocked(type, next_version_tag); assert (type->tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG); } else { @@ -9005,7 +9018,7 @@ type_ready_set_new(PyTypeObject *type, int initial) default also inherit object.__new__. */ if (type->tp_new == NULL && base == &PyBaseObject_Type - && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) + && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && initial) { type_add_flags(type, Py_TPFLAGS_DISALLOW_INSTANTIATION); } @@ -9021,13 +9034,21 @@ type_ready_set_new(PyTypeObject *type, int initial) } } else { - // tp_new is NULL: inherit tp_new from base - type->tp_new = base->tp_new; + if (initial) { + // tp_new is NULL: inherit tp_new from base + type->tp_new = base->tp_new; + } else { + assert(type->tp_new = base->tp_new); + } } } else { // Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL - type->tp_new = NULL; + if (initial) { + type->tp_new = NULL; + } else { + assert(type->tp_new == NULL); + } } return 0; } @@ -9160,7 +9181,9 @@ type_ready(PyTypeObject *type, int initial) } /* All done -- set the ready flag */ - type_add_flags(type, Py_TPFLAGS_READY); + if (initial) { + type_add_flags(type, Py_TPFLAGS_READY); + } stop_readying(type); assert(_PyType_CheckConsistency(type)); @@ -9209,15 +9232,16 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self, assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT)); assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF)); - if ((self->tp_flags & Py_TPFLAGS_READY) == 0) { - assert(initial); + if (initial) { + assert((self->tp_flags & Py_TPFLAGS_READY) == 0); type_add_flags(self, _Py_TPFLAGS_STATIC_BUILTIN); type_add_flags(self, Py_TPFLAGS_IMMUTABLETYPE); - assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG); if (self->tp_version_tag == 0) { - _PyType_SetVersion(self, NEXT_GLOBAL_VERSION_TAG++); + unsigned int next_version_tag = get_next_global_version_tag(); + assert(next_version_tag != (unsigned int)-1); + _PyType_SetVersion(self, next_version_tag); } } else { From 64f25bf88d353c3a906ea33599c4981e9e96819f Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 21 Jun 2025 22:53:29 +0530 Subject: [PATCH 2/4] more fixes --- Objects/typeobject.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index dd78fe3b6cfd60..d32722c7f59ebc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -265,8 +265,8 @@ static_ext_type_lookup(PyInterpreterState *interp, size_t index, assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); size_t full_index = index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; - int64_t interp_count = - _PyRuntime.types.managed_static.types[full_index].interp_count; + int64_t interp_count = _Py_atomic_load_int64( + &_PyRuntime.types.managed_static.types[full_index].interp_count); assert((interp_count == 0) == (_PyRuntime.types.managed_static.types[full_index].type == NULL)); *p_interp_count = interp_count; @@ -343,7 +343,7 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, : index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; assert((initial == 1) == - (_PyRuntime.types.managed_static.types[full_index].interp_count == 0)); + (_Py_atomic_load_int64(&_PyRuntime.types.managed_static.types[full_index].interp_count) == 0)); (void)_Py_atomic_add_int64( &_PyRuntime.types.managed_static.types[full_index].interp_count, 1); @@ -392,7 +392,7 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, : &(interp->types.for_extensions.initialized[index]); assert(state != NULL); - assert(_PyRuntime.types.managed_static.types[full_index].interp_count > 0); + assert(_Py_atomic_load_int64(&_PyRuntime.types.managed_static.types[full_index].interp_count) > 0); assert(_PyRuntime.types.managed_static.types[full_index].type == state->type); assert(state->type != NULL); @@ -402,7 +402,7 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, (void)_Py_atomic_add_int64( &_PyRuntime.types.managed_static.types[full_index].interp_count, -1); if (final) { - assert(!_PyRuntime.types.managed_static.types[full_index].interp_count); + assert(!_Py_atomic_load_int64(&_PyRuntime.types.managed_static.types[full_index].interp_count)); _PyRuntime.types.managed_static.types[full_index].type = NULL; managed_static_type_index_clear(self); @@ -9037,8 +9037,6 @@ type_ready_set_new(PyTypeObject *type, int initial) if (initial) { // tp_new is NULL: inherit tp_new from base type->tp_new = base->tp_new; - } else { - assert(type->tp_new = base->tp_new); } } } @@ -9046,8 +9044,6 @@ type_ready_set_new(PyTypeObject *type, int initial) // Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL if (initial) { type->tp_new = NULL; - } else { - assert(type->tp_new == NULL); } } return 0; @@ -9183,7 +9179,10 @@ type_ready(PyTypeObject *type, int initial) /* All done -- set the ready flag */ if (initial) { type_add_flags(type, Py_TPFLAGS_READY); + } else { + assert(type->tp_flags & Py_TPFLAGS_READY); } + stop_readying(type); assert(_PyType_CheckConsistency(type)); From 31435523f71a2b790333966004639e5cd707e0a4 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 2 Jul 2025 08:41:30 +0530 Subject: [PATCH 3/4] code review --- Objects/typeobject.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d32722c7f59ebc..72ee628650ab47 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1359,13 +1359,13 @@ _PyType_LookupByVersion(unsigned int version) #endif static inline unsigned int -get_next_global_version_tag(void) +next_global_version_tag(void) { unsigned int old; do { old = _Py_atomic_load_uint_relaxed(&_PyRuntime.types.next_version_tag); if (old >= _Py_MAX_GLOBAL_TYPE_VERSION_TAG) { - return (unsigned int)-1; + return 0; } } while (!_Py_atomic_compare_exchange_uint(&_PyRuntime.types.next_version_tag, &old, old + 1)); return old + 1; @@ -1401,8 +1401,8 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) } if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { /* static types */ - unsigned int next_version_tag = get_next_global_version_tag(); - if (next_version_tag == (unsigned int)-1) { + unsigned int next_version_tag = next_global_version_tag(); + if (next_version_tag == 0) { /* We have run out of version numbers */ return 0; } @@ -9238,8 +9238,8 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self, type_add_flags(self, Py_TPFLAGS_IMMUTABLETYPE); if (self->tp_version_tag == 0) { - unsigned int next_version_tag = get_next_global_version_tag(); - assert(next_version_tag != (unsigned int)-1); + unsigned int next_version_tag = next_global_version_tag(); + assert(next_version_tag != 0); _PyType_SetVersion(self, next_version_tag); } } From 75c5ea1c69d2db6bf629c4adea7fc3492085b8c1 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Fri, 4 Jul 2025 08:53:24 +0530 Subject: [PATCH 4/4] assert Py_TPFLAGS_DISALLOW_INSTANTIATION on initial=0 --- Objects/typeobject.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 50c11579b4ad88..e84278d13c3e9c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9018,9 +9018,13 @@ type_ready_set_new(PyTypeObject *type, int initial) default also inherit object.__new__. */ if (type->tp_new == NULL && base == &PyBaseObject_Type - && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && initial) + && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - type_add_flags(type, Py_TPFLAGS_DISALLOW_INSTANTIATION); + if (initial) { + type_add_flags(type, Py_TPFLAGS_DISALLOW_INSTANTIATION); + } else { + assert(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION); + } } if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) { 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