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()
This commit is contained in:
Victor Stinner 2022-01-21 01:42:25 +01:00 committed by GitHub
parent 27df7566bc
commit e9e3eab0b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 230 additions and 2 deletions

View file

@ -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)

View file

@ -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);
}

View file

@ -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)
{

View file

@ -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);