diff options
author | Victor Stinner <vstinner@python.org> | 2022-01-21 00:42:25 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-21 00:42:25 (GMT) |
commit | e9e3eab0b868c7d0b48e472705024240d5c39d5c (patch) | |
tree | 65c254d948a37dd822085887ebb84f390ad48d94 /Objects | |
parent | 27df7566bc19699b967e0e30d7808637b90141f6 (diff) | |
download | cpython-e9e3eab0b868c7d0b48e472705024240d5c39d5c.zip cpython-e9e3eab0b868c7d0b48e472705024240d5c39d5c.tar.gz cpython-e9e3eab0b868c7d0b48e472705024240d5c39d5c.tar.bz2 |
bpo-46417: Finalize structseq types at exit (GH-30645)
Add _PyStructSequence_FiniType() and _PyStaticType_Dealloc()
functions to finalize a structseq static type in Py_Finalize().
Currrently, these functions do nothing if Python is built in release
mode.
Clear static types:
* AsyncGenHooksType: sys.set_asyncgen_hooks()
* FlagsType: sys.flags
* FloatInfoType: sys.float_info
* Hash_InfoType: sys.hash_info
* Int_InfoType: sys.int_info
* ThreadInfoType: sys.thread_info
* UnraisableHookArgsType: sys.unraisablehook
* VersionInfoType: sys.version
* WindowsVersionType: sys.getwindowsversion()
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/floatobject.c | 8 | ||||
-rw-r--r-- | Objects/longobject.c | 11 | ||||
-rw-r--r-- | Objects/structseq.c | 30 | ||||
-rw-r--r-- | Objects/typeobject.c | 23 |
4 files changed, 70 insertions, 2 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c index f8620d6..88f25d6 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -2082,6 +2082,14 @@ _PyFloat_Fini(PyInterpreterState *interp) #endif } +void +_PyFloat_FiniType(PyInterpreterState *interp) +{ + if (_Py_IsMainInterpreter(interp)) { + _PyStructSequence_FiniType(&FloatInfoType); + } +} + /* Print summary info about the state of the optimized allocator */ void _PyFloat_DebugMallocStats(FILE *out) diff --git a/Objects/longobject.c b/Objects/longobject.c index 1b2d126..5aa53dd 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5949,3 +5949,14 @@ _PyLong_InitTypes(PyInterpreterState *interp) return _PyStatus_OK(); } + + +void +_PyLong_FiniTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + _PyStructSequence_FiniType(&Int_InfoType); +} diff --git a/Objects/structseq.c b/Objects/structseq.c index a2eefb0..f8bf947 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -532,6 +532,36 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) (void)PyStructSequence_InitType2(type, desc); } + +void +_PyStructSequence_FiniType(PyTypeObject *type) +{ + // Ensure that the type is initialized + assert(type->tp_name != NULL); + assert(type->tp_base == &PyTuple_Type); + + // Cannot delete a type if it still has subclasses + if (type->tp_subclasses != NULL) { + return; + } + + // Undo PyStructSequence_NewType() + type->tp_name = NULL; + PyMem_Free(type->tp_members); + + _PyStaticType_Dealloc(type); + assert(Py_REFCNT(type) == 1); + // Undo Py_INCREF(type) of _PyStructSequence_InitType(). + // Don't use Py_DECREF(): static type must not be deallocated + Py_SET_REFCNT(type, 0); + + // Make sure that _PyStructSequence_InitType() will initialize + // the type again + assert(Py_REFCNT(type) == 0); + assert(type->tp_name == NULL); +} + + PyTypeObject * PyStructSequence_NewType(PyStructSequence_Desc *desc) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index cbf806b..66a10a5 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4070,10 +4070,27 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) extern void _PyDictKeys_DecRef(PyDictKeysObject *keys); + +void +_PyStaticType_Dealloc(PyTypeObject *type) +{ + // _PyStaticType_Dealloc() must not be called if a type has subtypes. + // A subtype can inherit attributes and methods of its parent type, + // and a type must no longer be used once it's deallocated. + assert(type->tp_subclasses == NULL); + + Py_CLEAR(type->tp_dict); + Py_CLEAR(type->tp_bases); + Py_CLEAR(type->tp_mro); + Py_CLEAR(type->tp_cache); + Py_CLEAR(type->tp_subclasses); + type->tp_flags &= ~Py_TPFLAGS_READY; +} + + static void type_dealloc(PyTypeObject *type) { - PyHeapTypeObject *et; PyObject *tp, *val, *tb; /* Assert this is a heap-allocated type object */ @@ -4082,8 +4099,8 @@ type_dealloc(PyTypeObject *type) PyErr_Fetch(&tp, &val, &tb); remove_all_subclasses(type, type->tp_bases); PyErr_Restore(tp, val, tb); + PyObject_ClearWeakRefs((PyObject *)type); - et = (PyHeapTypeObject *)type; Py_XDECREF(type->tp_base); Py_XDECREF(type->tp_dict); Py_XDECREF(type->tp_bases); @@ -4094,6 +4111,8 @@ type_dealloc(PyTypeObject *type) * of most other objects. It's okay to cast it to char *. */ PyObject_Free((char *)type->tp_doc); + + PyHeapTypeObject *et = (PyHeapTypeObject *)type; Py_XDECREF(et->ht_name); Py_XDECREF(et->ht_qualname); Py_XDECREF(et->ht_slots); |