mirror of https://github.com/python/cpython
bpo-46417: Py_Finalize() clears static types (GH-30743)
Add _PyTypes_FiniTypes() best-effort function to clear static types: don't deallocate a type if it still has subclasses. remove_subclass() now sets tp_subclasses to NULL when removing the last subclass.
This commit is contained in:
parent
ea38e436fe
commit
595225e86d
|
@ -13,6 +13,7 @@ extern "C" {
|
||||||
|
|
||||||
extern PyStatus _PyTypes_InitState(PyInterpreterState *);
|
extern PyStatus _PyTypes_InitState(PyInterpreterState *);
|
||||||
extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
|
extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
|
||||||
|
extern void _PyTypes_FiniTypes(PyInterpreterState *);
|
||||||
extern void _PyTypes_Fini(PyInterpreterState *);
|
extern void _PyTypes_Fini(PyInterpreterState *);
|
||||||
|
|
||||||
|
|
||||||
|
|
199
Objects/object.c
199
Objects/object.c
|
@ -1837,6 +1837,94 @@ _PyTypes_InitState(PyInterpreterState *interp)
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyTypeObject* static_types[] = {
|
||||||
|
// base types
|
||||||
|
&PyAsyncGen_Type,
|
||||||
|
&PyBool_Type,
|
||||||
|
&PyByteArrayIter_Type,
|
||||||
|
&PyByteArray_Type,
|
||||||
|
&PyCFunction_Type,
|
||||||
|
&PyCallIter_Type,
|
||||||
|
&PyCapsule_Type,
|
||||||
|
&PyCell_Type,
|
||||||
|
&PyClassMethodDescr_Type,
|
||||||
|
&PyClassMethod_Type,
|
||||||
|
&PyCode_Type,
|
||||||
|
&PyComplex_Type,
|
||||||
|
&PyCoro_Type,
|
||||||
|
&PyDictItems_Type,
|
||||||
|
&PyDictIterItem_Type,
|
||||||
|
&PyDictIterKey_Type,
|
||||||
|
&PyDictIterValue_Type,
|
||||||
|
&PyDictKeys_Type,
|
||||||
|
&PyDictProxy_Type,
|
||||||
|
&PyDictRevIterItem_Type,
|
||||||
|
&PyDictRevIterKey_Type,
|
||||||
|
&PyDictRevIterValue_Type,
|
||||||
|
&PyDictValues_Type,
|
||||||
|
&PyDict_Type,
|
||||||
|
&PyEllipsis_Type,
|
||||||
|
&PyEnum_Type,
|
||||||
|
&PyFrame_Type,
|
||||||
|
&PyFrozenSet_Type,
|
||||||
|
&PyFunction_Type,
|
||||||
|
&PyGen_Type,
|
||||||
|
&PyGetSetDescr_Type,
|
||||||
|
&PyInstanceMethod_Type,
|
||||||
|
&PyListIter_Type,
|
||||||
|
&PyListRevIter_Type,
|
||||||
|
&PyList_Type,
|
||||||
|
&PyLongRangeIter_Type,
|
||||||
|
&PyMemberDescr_Type,
|
||||||
|
&PyMemoryView_Type,
|
||||||
|
&PyMethodDescr_Type,
|
||||||
|
&PyMethod_Type,
|
||||||
|
&PyModuleDef_Type,
|
||||||
|
&PyModule_Type,
|
||||||
|
&PyODictIter_Type,
|
||||||
|
&PyPickleBuffer_Type,
|
||||||
|
&PyProperty_Type,
|
||||||
|
&PyRangeIter_Type,
|
||||||
|
&PyRange_Type,
|
||||||
|
&PyReversed_Type,
|
||||||
|
&PySTEntry_Type,
|
||||||
|
&PySeqIter_Type,
|
||||||
|
&PySetIter_Type,
|
||||||
|
&PySet_Type,
|
||||||
|
&PySlice_Type,
|
||||||
|
&PyStaticMethod_Type,
|
||||||
|
&PyStdPrinter_Type,
|
||||||
|
&PySuper_Type,
|
||||||
|
&PyTraceBack_Type,
|
||||||
|
&PyWrapperDescr_Type,
|
||||||
|
&Py_GenericAliasType,
|
||||||
|
&_PyAnextAwaitable_Type,
|
||||||
|
&_PyAsyncGenASend_Type,
|
||||||
|
&_PyAsyncGenAThrow_Type,
|
||||||
|
&_PyAsyncGenWrappedValue_Type,
|
||||||
|
&_PyCoroWrapper_Type,
|
||||||
|
&_PyInterpreterID_Type,
|
||||||
|
&_PyManagedBuffer_Type,
|
||||||
|
&_PyMethodWrapper_Type,
|
||||||
|
&_PyNamespace_Type,
|
||||||
|
&_PyNone_Type,
|
||||||
|
&_PyNotImplemented_Type,
|
||||||
|
&_PyUnion_Type,
|
||||||
|
&_PyWeakref_CallableProxyType,
|
||||||
|
&_PyWeakref_ProxyType,
|
||||||
|
&_PyWeakref_RefType,
|
||||||
|
|
||||||
|
// subclasses: _PyTypes_FiniTypes() deallocates them before their base
|
||||||
|
// class
|
||||||
|
&PyCMethod_Type, // base=&PyCFunction_Type
|
||||||
|
&PyODictItems_Type, // base=&PyDictItems_Type
|
||||||
|
&PyODictKeys_Type, // base=&PyDictKeys_Type
|
||||||
|
&PyODictValues_Type, // base=&PyDictValues_Type
|
||||||
|
&PyODict_Type, // base=&PyDict_Type
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
PyStatus
|
PyStatus
|
||||||
_PyTypes_InitTypes(PyInterpreterState *interp)
|
_PyTypes_InitTypes(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
@ -1858,91 +1946,44 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
|
||||||
assert(PyType_Type.tp_base == &PyBaseObject_Type);
|
assert(PyType_Type.tp_base == &PyBaseObject_Type);
|
||||||
|
|
||||||
// All other static types (unless initialized elsewhere)
|
// All other static types (unless initialized elsewhere)
|
||||||
INIT_TYPE(PyAsyncGen_Type);
|
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
|
||||||
INIT_TYPE(PyBool_Type);
|
PyTypeObject *type = static_types[i];
|
||||||
INIT_TYPE(PyByteArrayIter_Type);
|
if (PyType_Ready(type) < 0) {
|
||||||
INIT_TYPE(PyByteArray_Type);
|
return _PyStatus_ERR("Can't initialize types");
|
||||||
INIT_TYPE(PyCFunction_Type);
|
}
|
||||||
INIT_TYPE(PyCMethod_Type);
|
}
|
||||||
INIT_TYPE(PyCallIter_Type);
|
|
||||||
INIT_TYPE(PyCapsule_Type);
|
|
||||||
INIT_TYPE(PyCell_Type);
|
|
||||||
INIT_TYPE(PyClassMethodDescr_Type);
|
|
||||||
INIT_TYPE(PyClassMethod_Type);
|
|
||||||
INIT_TYPE(PyCode_Type);
|
|
||||||
INIT_TYPE(PyComplex_Type);
|
|
||||||
INIT_TYPE(PyCoro_Type);
|
|
||||||
INIT_TYPE(PyDictItems_Type);
|
|
||||||
INIT_TYPE(PyDictIterItem_Type);
|
|
||||||
INIT_TYPE(PyDictIterKey_Type);
|
|
||||||
INIT_TYPE(PyDictIterValue_Type);
|
|
||||||
INIT_TYPE(PyDictKeys_Type);
|
|
||||||
INIT_TYPE(PyDictProxy_Type);
|
|
||||||
INIT_TYPE(PyDictRevIterItem_Type);
|
|
||||||
INIT_TYPE(PyDictRevIterKey_Type);
|
|
||||||
INIT_TYPE(PyDictRevIterValue_Type);
|
|
||||||
INIT_TYPE(PyDictValues_Type);
|
|
||||||
INIT_TYPE(PyDict_Type);
|
|
||||||
INIT_TYPE(PyEllipsis_Type);
|
|
||||||
INIT_TYPE(PyEnum_Type);
|
|
||||||
INIT_TYPE(PyFrame_Type);
|
|
||||||
INIT_TYPE(PyFrozenSet_Type);
|
|
||||||
INIT_TYPE(PyFunction_Type);
|
|
||||||
INIT_TYPE(PyGen_Type);
|
|
||||||
INIT_TYPE(PyGetSetDescr_Type);
|
|
||||||
INIT_TYPE(PyInstanceMethod_Type);
|
|
||||||
INIT_TYPE(PyListIter_Type);
|
|
||||||
INIT_TYPE(PyListRevIter_Type);
|
|
||||||
INIT_TYPE(PyList_Type);
|
|
||||||
INIT_TYPE(PyLongRangeIter_Type);
|
|
||||||
INIT_TYPE(PyMemberDescr_Type);
|
|
||||||
INIT_TYPE(PyMemoryView_Type);
|
|
||||||
INIT_TYPE(PyMethodDescr_Type);
|
|
||||||
INIT_TYPE(PyMethod_Type);
|
|
||||||
INIT_TYPE(PyModuleDef_Type);
|
|
||||||
INIT_TYPE(PyModule_Type);
|
|
||||||
INIT_TYPE(PyODictItems_Type);
|
|
||||||
INIT_TYPE(PyODictIter_Type);
|
|
||||||
INIT_TYPE(PyODictKeys_Type);
|
|
||||||
INIT_TYPE(PyODictValues_Type);
|
|
||||||
INIT_TYPE(PyODict_Type);
|
|
||||||
INIT_TYPE(PyPickleBuffer_Type);
|
|
||||||
INIT_TYPE(PyProperty_Type);
|
|
||||||
INIT_TYPE(PyRangeIter_Type);
|
|
||||||
INIT_TYPE(PyRange_Type);
|
|
||||||
INIT_TYPE(PyReversed_Type);
|
|
||||||
INIT_TYPE(PySTEntry_Type);
|
|
||||||
INIT_TYPE(PySeqIter_Type);
|
|
||||||
INIT_TYPE(PySetIter_Type);
|
|
||||||
INIT_TYPE(PySet_Type);
|
|
||||||
INIT_TYPE(PySlice_Type);
|
|
||||||
INIT_TYPE(PyStaticMethod_Type);
|
|
||||||
INIT_TYPE(PyStdPrinter_Type);
|
|
||||||
INIT_TYPE(PySuper_Type);
|
|
||||||
INIT_TYPE(PyTraceBack_Type);
|
|
||||||
INIT_TYPE(PyWrapperDescr_Type);
|
|
||||||
INIT_TYPE(Py_GenericAliasType);
|
|
||||||
INIT_TYPE(_PyAnextAwaitable_Type);
|
|
||||||
INIT_TYPE(_PyAsyncGenASend_Type);
|
|
||||||
INIT_TYPE(_PyAsyncGenAThrow_Type);
|
|
||||||
INIT_TYPE(_PyAsyncGenWrappedValue_Type);
|
|
||||||
INIT_TYPE(_PyCoroWrapper_Type);
|
|
||||||
INIT_TYPE(_PyInterpreterID_Type);
|
|
||||||
INIT_TYPE(_PyManagedBuffer_Type);
|
|
||||||
INIT_TYPE(_PyMethodWrapper_Type);
|
|
||||||
INIT_TYPE(_PyNamespace_Type);
|
|
||||||
INIT_TYPE(_PyNone_Type);
|
|
||||||
INIT_TYPE(_PyNotImplemented_Type);
|
|
||||||
INIT_TYPE(_PyWeakref_CallableProxyType);
|
|
||||||
INIT_TYPE(_PyWeakref_ProxyType);
|
|
||||||
INIT_TYPE(_PyWeakref_RefType);
|
|
||||||
INIT_TYPE(_PyUnion_Type);
|
|
||||||
|
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
#undef INIT_TYPE
|
#undef INIT_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Best-effort function clearing static types.
|
||||||
|
//
|
||||||
|
// Don't deallocate a type if it still has subclasses. If a Py_Finalize()
|
||||||
|
// sub-function is interrupted by CTRL+C or fails with MemoryError, some
|
||||||
|
// subclasses are not cleared properly. Leave the static type unchanged in this
|
||||||
|
// case.
|
||||||
|
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--) {
|
||||||
|
PyTypeObject *type = static_types[i];
|
||||||
|
// Cannot delete a type if it still has subclasses
|
||||||
|
if (type->tp_subclasses != NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_PyStaticType_Dealloc(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_Py_NewReference(PyObject *op)
|
_Py_NewReference(PyObject *op)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4071,6 +4071,18 @@ extern void
|
||||||
_PyDictKeys_DecRef(PyDictKeysObject *keys);
|
_PyDictKeys_DecRef(PyDictKeysObject *keys);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
type_dealloc_common(PyTypeObject *type)
|
||||||
|
{
|
||||||
|
PyObject *tp, *val, *tb;
|
||||||
|
PyErr_Fetch(&tp, &val, &tb);
|
||||||
|
remove_all_subclasses(type, type->tp_bases);
|
||||||
|
PyErr_Restore(tp, val, tb);
|
||||||
|
|
||||||
|
PyObject_ClearWeakRefs((PyObject *)type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyStaticType_Dealloc(PyTypeObject *type)
|
_PyStaticType_Dealloc(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
|
@ -4079,11 +4091,14 @@ _PyStaticType_Dealloc(PyTypeObject *type)
|
||||||
// and a type must no longer be used once it's deallocated.
|
// and a type must no longer be used once it's deallocated.
|
||||||
assert(type->tp_subclasses == NULL);
|
assert(type->tp_subclasses == NULL);
|
||||||
|
|
||||||
|
type_dealloc_common(type);
|
||||||
|
|
||||||
Py_CLEAR(type->tp_dict);
|
Py_CLEAR(type->tp_dict);
|
||||||
Py_CLEAR(type->tp_bases);
|
Py_CLEAR(type->tp_bases);
|
||||||
Py_CLEAR(type->tp_mro);
|
Py_CLEAR(type->tp_mro);
|
||||||
Py_CLEAR(type->tp_cache);
|
Py_CLEAR(type->tp_cache);
|
||||||
Py_CLEAR(type->tp_subclasses);
|
Py_CLEAR(type->tp_subclasses);
|
||||||
|
|
||||||
type->tp_flags &= ~Py_TPFLAGS_READY;
|
type->tp_flags &= ~Py_TPFLAGS_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4091,22 +4106,19 @@ _PyStaticType_Dealloc(PyTypeObject *type)
|
||||||
static void
|
static void
|
||||||
type_dealloc(PyTypeObject *type)
|
type_dealloc(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
PyObject *tp, *val, *tb;
|
|
||||||
|
|
||||||
/* Assert this is a heap-allocated type object */
|
/* Assert this is a heap-allocated type object */
|
||||||
_PyObject_ASSERT((PyObject *)type, type->tp_flags & Py_TPFLAGS_HEAPTYPE);
|
_PyObject_ASSERT((PyObject *)type, type->tp_flags & Py_TPFLAGS_HEAPTYPE);
|
||||||
_PyObject_GC_UNTRACK(type);
|
_PyObject_GC_UNTRACK(type);
|
||||||
PyErr_Fetch(&tp, &val, &tb);
|
|
||||||
remove_all_subclasses(type, type->tp_bases);
|
|
||||||
PyErr_Restore(tp, val, tb);
|
|
||||||
|
|
||||||
PyObject_ClearWeakRefs((PyObject *)type);
|
type_dealloc_common(type);
|
||||||
|
|
||||||
Py_XDECREF(type->tp_base);
|
Py_XDECREF(type->tp_base);
|
||||||
Py_XDECREF(type->tp_dict);
|
Py_XDECREF(type->tp_dict);
|
||||||
Py_XDECREF(type->tp_bases);
|
Py_XDECREF(type->tp_bases);
|
||||||
Py_XDECREF(type->tp_mro);
|
Py_XDECREF(type->tp_mro);
|
||||||
Py_XDECREF(type->tp_cache);
|
Py_XDECREF(type->tp_cache);
|
||||||
Py_XDECREF(type->tp_subclasses);
|
Py_XDECREF(type->tp_subclasses);
|
||||||
|
|
||||||
/* A type's tp_doc is heap allocated, unlike the tp_doc slots
|
/* A type's tp_doc is heap allocated, unlike the tp_doc slots
|
||||||
* of most other objects. It's okay to cast it to char *.
|
* of most other objects. It's okay to cast it to char *.
|
||||||
*/
|
*/
|
||||||
|
@ -6541,6 +6553,10 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type)
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
Py_XDECREF(key);
|
Py_XDECREF(key);
|
||||||
|
|
||||||
|
if (PyDict_Size(dict) == 0) {
|
||||||
|
Py_CLEAR(base->tp_subclasses);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -1676,6 +1676,7 @@ finalize_interp_types(PyInterpreterState *interp)
|
||||||
_PyThread_FiniType(interp);
|
_PyThread_FiniType(interp);
|
||||||
_PyErr_FiniTypes(interp);
|
_PyErr_FiniTypes(interp);
|
||||||
_PyTypes_Fini(interp);
|
_PyTypes_Fini(interp);
|
||||||
|
_PyTypes_FiniTypes(interp);
|
||||||
|
|
||||||
// Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses
|
// Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses
|
||||||
// a dict internally.
|
// a dict internally.
|
||||||
|
|
Loading…
Reference in New Issue