diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-25-23-55-43.gh-issue-116909.FGbNKx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-25-23-55-43.gh-issue-116909.FGbNKx.rst new file mode 100644 index 00000000000000..c11fbc88a45d5d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-25-23-55-43.gh-issue-116909.FGbNKx.rst @@ -0,0 +1 @@ +Fix crash upon importing a static type in a subinterpreter. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a7ab69fef4c721..ae76f56f988272 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 @@ -1258,6 +1257,25 @@ _PyType_GetVersionForCurrentState(PyTypeObject *tp) #error "_Py_ATTR_CACHE_UNUSED must be bigger than max" #endif +static int +get_next_global_version(unsigned int *dest) +{ + unsigned int v; + while (1) { + v = _Py_atomic_load_uint_relaxed(&_PyRuntime.types.next_version_tag); + + /* Stop if passed the maximum or we successfully updated the field */ + if (v > _Py_MAX_GLOBAL_TYPE_VERSION_TAG || + _Py_atomic_compare_exchange_uint(&_PyRuntime.types.next_version_tag, + &v, v + 1)) { + break; + } + } + + *dest = v; + return v <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG; +} + static int assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) { @@ -1288,11 +1306,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 version; + if (!get_next_global_version(&version)) { /* We have run out of version numbers */ return 0; } - set_version_unlocked(type, NEXT_GLOBAL_VERSION_TAG++); + set_version_unlocked(type, version); assert (type->tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG); } else { @@ -8877,9 +8896,12 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self, 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 version; + if (!get_next_global_version(&version)) { + assert(0 && "we have run out of version numbers"); + } + _PyType_SetVersion(self, version); } } else {