From dec8f6d7c7121c5a81529caa426800572c0f705d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 28 Apr 2023 16:10:30 -0600 Subject: [PATCH 01/14] Fix an old bug. --- Objects/typeobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 060d14e254ab2d..53c7915194cb5a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6938,7 +6938,8 @@ type_ready_post_checks(PyTypeObject *type) else if (type->tp_dictoffset < (Py_ssize_t)sizeof(PyObject)) { if (type->tp_dictoffset + type->tp_basicsize <= 0) { PyErr_Format(PyExc_SystemError, - "type %s has a tp_dictoffset that is too small"); + "type %s has a tp_dictoffset that is too small", + type->tp_name); } } return 0; From 98f3ed7e02ca70cf01e29bc9997d5033ddf0d738 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 16:27:13 -0600 Subject: [PATCH 02/14] Call _PyIO_FiniTypes() earlier. --- Python/pylifecycle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ba248d208e425a..a18e83ca8d6296 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1663,6 +1663,8 @@ flush_std_files(void) static void finalize_interp_types(PyInterpreterState *interp) { + _PyIO_FiniTypes(interp); + _PyUnicode_FiniTypes(interp); _PySys_Fini(interp); _PyExc_Fini(interp); @@ -1706,8 +1708,6 @@ finalize_interp_clear(PyThreadState *tstate) /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); - _PyIO_FiniTypes(tstate->interp); - /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. Call _PySys_ClearAuditHooks when PyObject available. */ From b3132936f341775e59a557eecc0206332653eeba Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 13:43:14 -0600 Subject: [PATCH 03/14] Pass interp to _PyStructSequence_InitBuiltin() and _PyStructSequence_FiniBuiltin(). --- Include/internal/pycore_structseq.h | 10 +++++++--- Objects/floatobject.c | 10 ++++++---- Objects/longobject.c | 6 ++++-- Objects/structseq.c | 5 +++-- Python/errors.c | 7 ++++--- Python/sysmodule.c | 30 +++++++++++++++++------------ Python/thread.c | 5 +++-- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/Include/internal/pycore_structseq.h b/Include/internal/pycore_structseq.h index bd1e85c6883f01..6f5dfc12707cf8 100644 --- a/Include/internal/pycore_structseq.h +++ b/Include/internal/pycore_structseq.h @@ -16,18 +16,22 @@ PyAPI_FUNC(PyTypeObject *) _PyStructSequence_NewType( unsigned long tp_flags); extern int _PyStructSequence_InitBuiltinWithFlags( + PyInterpreterState *interp, PyTypeObject *type, PyStructSequence_Desc *desc, unsigned long tp_flags); static inline int -_PyStructSequence_InitBuiltin(PyTypeObject *type, +_PyStructSequence_InitBuiltin(PyInterpreterState *interp, + PyTypeObject *type, PyStructSequence_Desc *desc) { - return _PyStructSequence_InitBuiltinWithFlags(type, desc, 0); + return _PyStructSequence_InitBuiltinWithFlags(interp, type, desc, 0); } -extern void _PyStructSequence_FiniBuiltin(PyTypeObject *type); +extern void _PyStructSequence_FiniBuiltin( + PyInterpreterState *interp, + PyTypeObject *type); #ifdef __cplusplus } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index a694ddcd019ee8..5ac101414da110 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1991,8 +1991,9 @@ PyStatus _PyFloat_InitTypes(PyInterpreterState *interp) { /* Init float info */ - if (_PyStructSequence_InitBuiltin(&FloatInfoType, - &floatinfo_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &FloatInfoType, + &floatinfo_desc) < 0) + { return _PyStatus_ERR("can't init float info type"); } @@ -2028,9 +2029,10 @@ _PyFloat_Fini(PyInterpreterState *interp) void _PyFloat_FiniType(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(interp)) { - _PyStructSequence_FiniBuiltin(&FloatInfoType); + if (!_Py_IsMainInterpreter(interp)) { + return; } + _PyStructSequence_FiniBuiltin(interp, &FloatInfoType); } /* Print summary info about the state of the optimized allocator */ diff --git a/Objects/longobject.c b/Objects/longobject.c index de043488d7a173..e2174fb6fe7ecf 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6352,7 +6352,9 @@ PyStatus _PyLong_InitTypes(PyInterpreterState *interp) { /* initialize int_info */ - if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &Int_InfoType, + &int_info_desc) < 0) + { return _PyStatus_ERR("can't init int info type"); } @@ -6367,5 +6369,5 @@ _PyLong_FiniTypes(PyInterpreterState *interp) return; } - _PyStructSequence_FiniBuiltin(&Int_InfoType); + _PyStructSequence_FiniBuiltin(interp, &Int_InfoType); } diff --git a/Objects/structseq.c b/Objects/structseq.c index d8f55dc1eae5ed..86129a82b019fc 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -502,7 +502,8 @@ initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc, } int -_PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type, +_PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, + PyTypeObject *type, PyStructSequence_Desc *desc, unsigned long tp_flags) { @@ -606,7 +607,7 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) initialized via _PyStructSequence_InitBuiltinWithFlags(). */ void -_PyStructSequence_FiniBuiltin(PyTypeObject *type) +_PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type) { // Ensure that the type is initialized assert(type->tp_name != NULL); diff --git a/Python/errors.c b/Python/errors.c index ce72049b92de27..41fea6b87ff2e6 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1342,8 +1342,9 @@ static PyStructSequence_Desc UnraisableHookArgs_desc = { PyStatus _PyErr_InitTypes(PyInterpreterState *interp) { - if (_PyStructSequence_InitBuiltin(&UnraisableHookArgsType, - &UnraisableHookArgs_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &UnraisableHookArgsType, + &UnraisableHookArgs_desc) < 0) + { return _PyStatus_ERR("failed to initialize UnraisableHookArgs type"); } return _PyStatus_OK(); @@ -1357,7 +1358,7 @@ _PyErr_FiniTypes(PyInterpreterState *interp) return; } - _PyStructSequence_FiniBuiltin(&UnraisableHookArgsType); + _PyStructSequence_FiniBuiltin(interp, &UnraisableHookArgsType); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 81dabe6102f18d..1a22ffc0530411 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3141,6 +3141,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) { PyObject *version_info; int res; + PyInterpreterState *interp = tstate->interp; /* stdin/stdout/stderr are set in pylifecycle.c */ @@ -3166,7 +3167,9 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("float_info", PyFloat_GetInfo()); SET_SYS("int_info", PyLong_GetInfo()); /* initialize hash_info */ - if (_PyStructSequence_InitBuiltin(&Hash_InfoType, &hash_info_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &Hash_InfoType, + &hash_info_desc) < 0) + { goto type_init_failed; } SET_SYS("hash_info", get_hash_info(tstate)); @@ -3190,7 +3193,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) #define ENSURE_INFO_TYPE(TYPE, DESC) \ do { \ if (_PyStructSequence_InitBuiltinWithFlags( \ - &TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \ + interp, &TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \ goto type_init_failed; \ } \ } while (0) @@ -3226,8 +3229,9 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); /* initialize asyncgen_hooks */ - if (_PyStructSequence_InitBuiltin( - &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, + &asyncgen_hooks_desc) < 0) + { goto type_init_failed; } @@ -3491,18 +3495,20 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) void _PySys_Fini(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(interp)) { - _PyStructSequence_FiniBuiltin(&VersionInfoType); - _PyStructSequence_FiniBuiltin(&FlagsType); + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + _PyStructSequence_FiniBuiltin(interp, &VersionInfoType); + _PyStructSequence_FiniBuiltin(interp, &FlagsType); #if defined(MS_WINDOWS) - _PyStructSequence_FiniBuiltin(&WindowsVersionType); + _PyStructSequence_FiniBuiltin(interp, &WindowsVersionType); #endif - _PyStructSequence_FiniBuiltin(&Hash_InfoType); - _PyStructSequence_FiniBuiltin(&AsyncGenHooksType); + _PyStructSequence_FiniBuiltin(interp, &Hash_InfoType); + _PyStructSequence_FiniBuiltin(interp, &AsyncGenHooksType); #ifdef __EMSCRIPTEN__ - Py_CLEAR(EmscriptenInfoType); + Py_CLEAR(EmscriptenInfoType); #endif - } } diff --git a/Python/thread.c b/Python/thread.c index f90cd34a073540..34134addfd45f6 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -137,7 +137,8 @@ PyThread_GetInfo(void) int len; #endif - if (_PyStructSequence_InitBuiltin(&ThreadInfoType, &threadinfo_desc) < 0) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (_PyStructSequence_InitBuiltin(interp, &ThreadInfoType, &threadinfo_desc) < 0) { return NULL; } @@ -195,5 +196,5 @@ _PyThread_FiniType(PyInterpreterState *interp) return; } - _PyStructSequence_FiniBuiltin(&ThreadInfoType); + _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType); } From 4a78881aa023083c27d57c36233b167f54eb05f2 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 14:09:05 -0600 Subject: [PATCH 04/14] Pass interp to _PyStaticType_InitBuiltin() and _PyStaticType_Dealloc(). --- Include/internal/pycore_object.h | 3 +- Include/internal/pycore_typeobject.h | 8 +++--- Modules/_io/_iomodule.c | 4 +-- Objects/exceptions.c | 4 +-- Objects/object.c | 4 +-- Objects/structseq.c | 16 ++++++----- Objects/typeobject.c | 41 ++++++++++++++-------------- Objects/unicodeobject.c | 12 ++++---- Objects/weakrefobject.c | 4 +-- 9 files changed, 49 insertions(+), 47 deletions(-) diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 2ca047846e0935..2ee0180c0554d2 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -272,8 +272,9 @@ _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) { if (PyType_Check(op) && ((PyTypeObject *)op)->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); static_builtin_state *state = _PyStaticType_GetState( - (PyTypeObject *)op); + interp, (PyTypeObject *)op); return _PyStaticType_GET_WEAKREFS_LISTPTR(state); } // Essentially _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(): diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 76253fd5fd864c..5bd04736c01d2d 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -104,10 +104,10 @@ _PyType_GetModuleState(PyTypeObject *type) } -extern int _PyStaticType_InitBuiltin(PyTypeObject *type); -extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *); -extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); -extern void _PyStaticType_Dealloc(PyTypeObject *type); +extern int _PyStaticType_InitBuiltin(PyInterpreterState *, PyTypeObject *type); +extern static_builtin_state * _PyStaticType_GetState(PyInterpreterState *, PyTypeObject *); +extern void _PyStaticType_ClearWeakRefs(PyInterpreterState *, PyTypeObject *type); +extern void _PyStaticType_Dealloc(PyInterpreterState *, PyTypeObject *); PyObject * _Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress_missing_attribute); diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index a3bfbc9ac5a1b1..e8a1f9aa3ab1dd 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -680,7 +680,7 @@ _PyIO_InitTypes(PyInterpreterState *interp) for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; - if (_PyStaticType_InitBuiltin(type) < 0) { + if (_PyStaticType_InitBuiltin(interp, type) < 0) { return _PyStatus_ERR("Can't initialize builtin type"); } } @@ -699,7 +699,7 @@ _PyIO_FiniTypes(PyInterpreterState *interp) // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { PyTypeObject *type = static_types[i]; - _PyStaticType_Dealloc(type); + _PyStaticType_Dealloc(interp, type); } } diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 6c9dfbd9b415cf..77a8789853df5e 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3598,7 +3598,7 @@ _PyExc_InitTypes(PyInterpreterState *interp) { for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) { PyTypeObject *exc = static_exceptions[i].exc; - if (_PyStaticType_InitBuiltin(exc) < 0) { + if (_PyStaticType_InitBuiltin(interp, exc) < 0) { return -1; } } @@ -3615,7 +3615,7 @@ _PyExc_FiniTypes(PyInterpreterState *interp) for (Py_ssize_t i=Py_ARRAY_LENGTH(static_exceptions) - 1; i >= 0; i--) { PyTypeObject *exc = static_exceptions[i].exc; - _PyStaticType_Dealloc(exc); + _PyStaticType_Dealloc(interp, exc); } } diff --git a/Objects/object.c b/Objects/object.c index 4ce10cf1192d3f..a8b05786dd4b06 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2105,7 +2105,7 @@ _PyTypes_InitTypes(PyInterpreterState *interp) // All other static types (unless initialized elsewhere) for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; - if (_PyStaticType_InitBuiltin(type) < 0) { + if (_PyStaticType_InitBuiltin(interp, type) < 0) { return _PyStatus_ERR("Can't initialize builtin type"); } if (type == &PyType_Type) { @@ -2136,7 +2136,7 @@ _PyTypes_FiniTypes(PyInterpreterState *interp) // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) { PyTypeObject *type = static_types[i]; - _PyStaticType_Dealloc(type); + _PyStaticType_Dealloc(interp, type); } } diff --git a/Objects/structseq.c b/Objects/structseq.c index 86129a82b019fc..ea476bf7a6a954 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -537,7 +537,7 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, } #endif - if (_PyStaticType_InitBuiltin(type) < 0) { + if (_PyStaticType_InitBuiltin(interp, type) < 0) { PyErr_Format(PyExc_RuntimeError, "Can't initialize builtin type %s", desc->name); @@ -621,13 +621,15 @@ _PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type) return; } - _PyStaticType_Dealloc(type); + _PyStaticType_Dealloc(interp, type); - // Undo _PyStructSequence_InitBuiltinWithFlags(). - type->tp_name = NULL; - PyMem_Free(type->tp_members); - type->tp_members = NULL; - type->tp_base = NULL; + if (_Py_IsMainInterpreter(interp)) { + // Undo _PyStructSequence_InitBuiltinWithFlags(). + type->tp_name = NULL; + PyMem_Free(type->tp_members); + type->tp_members = NULL; + type->tp_base = NULL; + } } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 53c7915194cb5a..10a117e29dde0a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -107,19 +107,16 @@ static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self) /* For static types we store some state in an array on each interpreter. */ static_builtin_state * -_PyStaticType_GetState(PyTypeObject *self) +_PyStaticType_GetState(PyInterpreterState *interp, PyTypeObject *self) { assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); - PyInterpreterState *interp = _PyInterpreterState_GET(); return static_builtin_state_get(interp, self); } +/* Set the type's per-interpreter state. */ static void -static_builtin_state_init(PyTypeObject *self) +static_builtin_state_init(PyInterpreterState *interp, PyTypeObject *self) { - /* Set the type's per-interpreter state. */ - PyInterpreterState *interp = _PyInterpreterState_GET(); - /* It should only be called once for each builtin type. */ assert(!static_builtin_index_is_set(self)); @@ -133,13 +130,11 @@ static_builtin_state_init(PyTypeObject *self) (in weakrefobject.c) sets it. */ } +/* Reset the type's per-interpreter state. + This basically undoes what static_builtin_state_init() did. */ static void -static_builtin_state_clear(PyTypeObject *self) +static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self) { - /* Reset the type's per-interpreter state. - This basically undoes what static_builtin_state_init() did. */ - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = static_builtin_state_get(interp, self); state->type = NULL; assert(state->tp_weaklist == NULL); // It was already cleared out. @@ -4492,7 +4487,7 @@ clear_static_tp_subclasses(PyTypeObject *type) } void -_PyStaticType_Dealloc(PyTypeObject *type) +_PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) { assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)); @@ -4514,8 +4509,8 @@ _PyStaticType_Dealloc(PyTypeObject *type) type->tp_version_tag = 0; if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - _PyStaticType_ClearWeakRefs(type); - static_builtin_state_clear(type); + _PyStaticType_ClearWeakRefs(interp, type); + static_builtin_state_clear(interp, type); /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ } } @@ -4564,7 +4559,8 @@ static PyObject * lookup_subclasses(PyTypeObject *self) { if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - static_builtin_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); assert(state != NULL); return state->tp_subclasses; } @@ -4574,8 +4570,9 @@ lookup_subclasses(PyTypeObject *self) int _PyType_HasSubclasses(PyTypeObject *self) { + PyInterpreterState *interp = _PyInterpreterState_GET(); if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN && - _PyStaticType_GetState(self) == NULL) { + _PyStaticType_GetState(interp, self) == NULL) { return 0; } if (lookup_subclasses(self) == NULL) { @@ -7030,7 +7027,7 @@ PyType_Ready(PyTypeObject *type) } int -_PyStaticType_InitBuiltin(PyTypeObject *self) +_PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) { assert(_Py_IsImmortal((PyObject *)self)); assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE)); @@ -7048,11 +7045,11 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++; self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; - static_builtin_state_init(self); + static_builtin_state_init(interp, self); int res = type_ready(self); if (res < 0) { - static_builtin_state_clear(self); + static_builtin_state_clear(interp, self); } return res; } @@ -7066,7 +7063,8 @@ init_subclasses(PyTypeObject *self) return NULL; } if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - static_builtin_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); state->tp_subclasses = subclasses; return subclasses; } @@ -7081,7 +7079,8 @@ clear_subclasses(PyTypeObject *self) callers also test if tp_subclasses is NULL to check if a static type has no subclass. */ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - static_builtin_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); Py_CLEAR(state->tp_subclasses); return; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7537c12e92680c..76ab5fb9eec576 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14573,13 +14573,13 @@ _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) PyStatus _PyUnicode_InitTypes(PyInterpreterState *interp) { - if (_PyStaticType_InitBuiltin(&EncodingMapType) < 0) { + if (_PyStaticType_InitBuiltin(interp, &EncodingMapType) < 0) { goto error; } - if (_PyStaticType_InitBuiltin(&PyFieldNameIter_Type) < 0) { + if (_PyStaticType_InitBuiltin(interp, &PyFieldNameIter_Type) < 0) { goto error; } - if (_PyStaticType_InitBuiltin(&PyFormatterIter_Type) < 0) { + if (_PyStaticType_InitBuiltin(interp, &PyFormatterIter_Type) < 0) { goto error; } return _PyStatus_OK(); @@ -15162,9 +15162,9 @@ _PyUnicode_FiniTypes(PyInterpreterState *interp) return; } - _PyStaticType_Dealloc(&EncodingMapType); - _PyStaticType_Dealloc(&PyFieldNameIter_Type); - _PyStaticType_Dealloc(&PyFormatterIter_Type); + _PyStaticType_Dealloc(interp, &EncodingMapType); + _PyStaticType_Dealloc(interp, &PyFieldNameIter_Type); + _PyStaticType_Dealloc(interp, &PyFormatterIter_Type); } diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index c1afe63ecf66f6..aee79fc1410b29 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -1017,9 +1017,9 @@ PyObject_ClearWeakRefs(PyObject *object) * or anything else. */ void -_PyStaticType_ClearWeakRefs(PyTypeObject *type) +_PyStaticType_ClearWeakRefs(PyInterpreterState *interp, PyTypeObject *type) { - static_builtin_state *state = _PyStaticType_GetState(type); + static_builtin_state *state = _PyStaticType_GetState(interp, type); PyObject **list = _PyStaticType_GET_WEAKREFS_LISTPTR(state); while (*list != NULL) { /* Note that clear_weakref() pops the first ref off the type's From 4355c00d04f58438029acf5ea6a2a4418cab0e19 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 14:36:49 -0600 Subject: [PATCH 05/14] Add clear_static_type_objects(). --- Objects/typeobject.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 10a117e29dde0a..8d29826618a0a7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4486,6 +4486,18 @@ clear_static_tp_subclasses(PyTypeObject *type) clear_subclasses(type); } +static void +clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type) +{ + if (_Py_IsMainInterpreter(interp)) { + Py_CLEAR(type->tp_dict); + Py_CLEAR(type->tp_bases); + Py_CLEAR(type->tp_mro); + Py_CLEAR(type->tp_cache); + } + clear_static_tp_subclasses(type); +} + void _PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) { @@ -4493,11 +4505,7 @@ _PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) type_dealloc_common(type); - Py_CLEAR(type->tp_dict); - Py_CLEAR(type->tp_bases); - Py_CLEAR(type->tp_mro); - Py_CLEAR(type->tp_cache); - clear_static_tp_subclasses(type); + clear_static_type_objects(interp, type); // PyObject_ClearWeakRefs() raises an exception if Py_REFCNT() != 0 if (Py_REFCNT(type) == 0) { From 7dd7d96cda275b8f1319abff854f5d3f207caf6a Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 15:23:06 -0600 Subject: [PATCH 06/14] Builtin static types are always immortal. --- Objects/typeobject.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8d29826618a0a7..806e7847ceb8aa 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4502,16 +4502,12 @@ void _PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) { assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)); + assert(_Py_IsImmortal((PyObject *)type)); type_dealloc_common(type); clear_static_type_objects(interp, type); - // PyObject_ClearWeakRefs() raises an exception if Py_REFCNT() != 0 - if (Py_REFCNT(type) == 0) { - PyObject_ClearWeakRefs((PyObject *)type); - } - type->tp_flags &= ~Py_TPFLAGS_READY; type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; From f678350b5328b64ff446c9c04069c09a94232fd0 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 15:29:23 -0600 Subject: [PATCH 07/14] _PyStaticType_Dealloc() is only called on static builtin types. --- Objects/typeobject.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 806e7847ceb8aa..191ca5fdf01a58 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4501,7 +4501,7 @@ clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type) void _PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) { - assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)); + assert(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); assert(_Py_IsImmortal((PyObject *)type)); type_dealloc_common(type); @@ -4512,11 +4512,9 @@ _PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; - if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - _PyStaticType_ClearWeakRefs(interp, type); - static_builtin_state_clear(interp, type); - /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ - } + _PyStaticType_ClearWeakRefs(interp, type); + static_builtin_state_clear(interp, type); + /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ } From eeeff5277ea98fb60700b91387b154508acb22b0 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 15:46:14 -0600 Subject: [PATCH 08/14] Set the proper relationship between static builtin types and the subinterpreters. --- Objects/typeobject.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 191ca5fdf01a58..880c8b7b08fd6e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4508,9 +4508,11 @@ _PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) clear_static_type_objects(interp, type); - type->tp_flags &= ~Py_TPFLAGS_READY; - type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; - type->tp_version_tag = 0; + if (_Py_IsMainInterpreter(interp)) { + type->tp_flags &= ~Py_TPFLAGS_READY; + type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + type->tp_version_tag = 0; + } _PyStaticType_ClearWeakRefs(interp, type); static_builtin_state_clear(interp, type); @@ -7037,9 +7039,13 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) if (self->tp_flags & Py_TPFLAGS_READY) { assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); assert(_PyType_CheckConsistency(self)); + /* Per-interpreter tp_subclasses is done lazily. + Otherwise we would initialize it here. */ return 0; } + assert(_Py_IsMainInterpreter(interp)); + self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN; self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; From ae74c412737c4ba3c9cfaaf95831347a3736037b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 16:28:14 -0600 Subject: [PATCH 09/14] Set the static builtin index correctly. --- Objects/typeobject.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 880c8b7b08fd6e..3ee78ef35e678b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -117,17 +117,20 @@ _PyStaticType_GetState(PyInterpreterState *interp, PyTypeObject *self) static void static_builtin_state_init(PyInterpreterState *interp, PyTypeObject *self) { - /* It should only be called once for each builtin type. */ - assert(!static_builtin_index_is_set(self)); - - static_builtin_index_set(self, interp->types.num_builtins_initialized); - interp->types.num_builtins_initialized++; - + if (!static_builtin_index_is_set(self)) { + static_builtin_index_set(self, interp->types.num_builtins_initialized); + } static_builtin_state *state = static_builtin_state_get(interp, self); + + /* It should only be called once for each builtin type. */ + assert(state->type == NULL); state->type = self; + /* state->tp_subclasses is left NULL until init_subclasses() sets it. */ /* state->tp_weaklist is left NULL until insert_head() or insert_after() (in weakrefobject.c) sets it. */ + + interp->types.num_builtins_initialized++; } /* Reset the type's per-interpreter state. @@ -136,8 +139,11 @@ static void static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self) { static_builtin_state *state = static_builtin_state_get(interp, self); + + assert(state->type != NULL); state->type = NULL; assert(state->tp_weaklist == NULL); // It was already cleared out. + static_builtin_index_clear(self); assert(interp->types.num_builtins_initialized > 0); From f2fb5a48ecf6878d47e4e48b706551f70f15e0ed Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 17:30:43 -0600 Subject: [PATCH 10/14] Add some asserts. --- Objects/typeobject.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 3ee78ef35e678b..52a75a19e3774a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7041,16 +7041,23 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) { assert(_Py_IsImmortal((PyObject *)self)); assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE)); + assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT)); + assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF)); + int ismain = _Py_IsMainInterpreter(interp); if (self->tp_flags & Py_TPFLAGS_READY) { + assert(!ismain); assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); - assert(_PyType_CheckConsistency(self)); + assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG); + /* Per-interpreter tp_subclasses is done lazily. Otherwise we would initialize it here. */ + + assert(_PyType_CheckConsistency(self)); return 0; } - assert(_Py_IsMainInterpreter(interp)); + assert(ismain); self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN; self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; From 51d325d4079b7eea2fc054c169d36f29c029040f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 17:36:46 -0600 Subject: [PATCH 11/14] Call static_builtin_state_init() for each interpreter. --- Objects/typeobject.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 52a75a19e3774a..4d6175bfc08f06 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7050,6 +7050,8 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG); + static_builtin_state_init(interp, self); + /* Per-interpreter tp_subclasses is done lazily. Otherwise we would initialize it here. */ From 71e52c2a89acff3fcd0e7a3de1b7bda1c49a826b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 17:54:30 -0600 Subject: [PATCH 12/14] Only call static_builtin_index_clear() during runtime fini. --- Objects/typeobject.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4d6175bfc08f06..fbe7b7f565bb36 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -144,7 +144,9 @@ static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self) state->type = NULL; assert(state->tp_weaklist == NULL); // It was already cleared out. - static_builtin_index_clear(self); + if (_Py_IsMainInterpreter(interp)) { + static_builtin_index_clear(self); + } assert(interp->types.num_builtins_initialized > 0); interp->types.num_builtins_initialized--; From f41a74d551571bffe8fb39772b63dfab1198f77c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 13:15:53 -0600 Subject: [PATCH 13/14] Finalize static builtin types for each interpreter. --- Include/internal/pycore_pylifecycle.h | 2 +- Modules/_io/_iomodule.c | 4 ---- Objects/exceptions.c | 4 ---- Objects/floatobject.c | 3 --- Objects/longobject.c | 5 ----- Objects/object.c | 4 ---- Objects/unicodeobject.c | 4 ---- Python/errors.c | 4 ---- Python/pylifecycle.c | 2 +- Python/sysmodule.c | 10 ++++------ Python/thread.c | 4 ---- 11 files changed, 6 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index f96261a650dac7..7f8cc643ec0c96 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -39,7 +39,7 @@ extern PyStatus _PySys_Create( extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options); extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config); extern int _PySys_UpdateConfig(PyThreadState *tstate); -extern void _PySys_Fini(PyInterpreterState *interp); +extern void _PySys_FiniTypes(PyInterpreterState *interp); extern int _PyBuiltins_AddExceptions(PyObject * bltinmod); extern PyStatus _Py_HashRandomization_Init(const PyConfig *); diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index e8a1f9aa3ab1dd..8ec3a6081c98d9 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -691,10 +691,6 @@ _PyIO_InitTypes(PyInterpreterState *interp) void _PyIO_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - // Deallocate types in the reverse order to deallocate subclasses before // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 77a8789853df5e..ba5ee291f08b0c 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3609,10 +3609,6 @@ _PyExc_InitTypes(PyInterpreterState *interp) static void _PyExc_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - for (Py_ssize_t i=Py_ARRAY_LENGTH(static_exceptions) - 1; i >= 0; i--) { PyTypeObject *exc = static_exceptions[i].exc; _PyStaticType_Dealloc(interp, exc); diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 5ac101414da110..d257857d9c619c 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -2029,9 +2029,6 @@ _PyFloat_Fini(PyInterpreterState *interp) void _PyFloat_FiniType(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } _PyStructSequence_FiniBuiltin(interp, &FloatInfoType); } diff --git a/Objects/longobject.c b/Objects/longobject.c index e2174fb6fe7ecf..853e934e2107ea 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -7,7 +7,6 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _Py_SmallInts #include "pycore_object.h" // _PyObject_Init() -#include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() @@ -6365,9 +6364,5 @@ _PyLong_InitTypes(PyInterpreterState *interp) void _PyLong_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - _PyStructSequence_FiniBuiltin(interp, &Int_InfoType); } diff --git a/Objects/object.c b/Objects/object.c index a8b05786dd4b06..ee8690101d3cc0 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2128,10 +2128,6 @@ _PyTypes_InitTypes(PyInterpreterState *interp) void _PyTypes_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - // Deallocate types in the reverse order to deallocate subclasses before // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) { diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 76ab5fb9eec576..6ae68cc20f7dee 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15158,10 +15158,6 @@ unicode_is_finalizing(void) void _PyUnicode_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - _PyStaticType_Dealloc(interp, &EncodingMapType); _PyStaticType_Dealloc(interp, &PyFieldNameIter_Type); _PyStaticType_Dealloc(interp, &PyFormatterIter_Type); diff --git a/Python/errors.c b/Python/errors.c index 41fea6b87ff2e6..a8000ac94918db 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1354,10 +1354,6 @@ _PyErr_InitTypes(PyInterpreterState *interp) void _PyErr_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - _PyStructSequence_FiniBuiltin(interp, &UnraisableHookArgsType); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index a18e83ca8d6296..b8a115236900b9 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1666,7 +1666,7 @@ finalize_interp_types(PyInterpreterState *interp) _PyIO_FiniTypes(interp); _PyUnicode_FiniTypes(interp); - _PySys_Fini(interp); + _PySys_FiniTypes(interp); _PyExc_Fini(interp); _PyAsyncGen_Fini(interp); _PyContext_Fini(interp); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 1a22ffc0530411..781588b0df4ead 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3493,12 +3493,8 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) void -_PySys_Fini(PyInterpreterState *interp) +_PySys_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - _PyStructSequence_FiniBuiltin(interp, &VersionInfoType); _PyStructSequence_FiniBuiltin(interp, &FlagsType); #if defined(MS_WINDOWS) @@ -3507,7 +3503,9 @@ _PySys_Fini(PyInterpreterState *interp) _PyStructSequence_FiniBuiltin(interp, &Hash_InfoType); _PyStructSequence_FiniBuiltin(interp, &AsyncGenHooksType); #ifdef __EMSCRIPTEN__ - Py_CLEAR(EmscriptenInfoType); + if (_Py_IsMainInterpreter(interp)) { + Py_CLEAR(EmscriptenInfoType); + } #endif } diff --git a/Python/thread.c b/Python/thread.c index 34134addfd45f6..7fc53f9b61360b 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -192,9 +192,5 @@ PyThread_GetInfo(void) void _PyThread_FiniType(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType); } From 68331c45fc5b947961088509b0b7de0dcb068e85 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 1 May 2023 19:01:12 -0600 Subject: [PATCH 14/14] Fix non-debug builds. --- Objects/typeobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index fbe7b7f565bb36..2ed806fb01554f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -69,13 +69,11 @@ static inline PyTypeObject * subclass_from_ref(PyObject *ref); /* helpers for for static builtin types */ -#ifndef NDEBUG static inline int static_builtin_index_is_set(PyTypeObject *self) { return self->tp_subclasses != NULL; } -#endif static inline size_t static_builtin_index_get(PyTypeObject *self) @@ -7046,7 +7044,9 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT)); assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF)); +#ifndef NDEBUG int ismain = _Py_IsMainInterpreter(interp); +#endif if (self->tp_flags & Py_TPFLAGS_READY) { assert(!ismain); assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);