Skip to content

Commit 595225e

Browse files
authored
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.
1 parent ea38e43 commit 595225e

File tree

4 files changed

+144
-85
lines changed

4 files changed

+144
-85
lines changed

Include/internal/pycore_typeobject.h

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern "C" {
1313

1414
extern PyStatus _PyTypes_InitState(PyInterpreterState *);
1515
extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
16+
extern void _PyTypes_FiniTypes(PyInterpreterState *);
1617
extern void _PyTypes_Fini(PyInterpreterState *);
1718

1819

Objects/object.c

+120-79
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,94 @@ _PyTypes_InitState(PyInterpreterState *interp)
18371837
return _PyStatus_OK();
18381838
}
18391839

1840+
1841+
static PyTypeObject* static_types[] = {
1842+
// base types
1843+
&PyAsyncGen_Type,
1844+
&PyBool_Type,
1845+
&PyByteArrayIter_Type,
1846+
&PyByteArray_Type,
1847+
&PyCFunction_Type,
1848+
&PyCallIter_Type,
1849+
&PyCapsule_Type,
1850+
&PyCell_Type,
1851+
&PyClassMethodDescr_Type,
1852+
&PyClassMethod_Type,
1853+
&PyCode_Type,
1854+
&PyComplex_Type,
1855+
&PyCoro_Type,
1856+
&PyDictItems_Type,
1857+
&PyDictIterItem_Type,
1858+
&PyDictIterKey_Type,
1859+
&PyDictIterValue_Type,
1860+
&PyDictKeys_Type,
1861+
&PyDictProxy_Type,
1862+
&PyDictRevIterItem_Type,
1863+
&PyDictRevIterKey_Type,
1864+
&PyDictRevIterValue_Type,
1865+
&PyDictValues_Type,
1866+
&PyDict_Type,
1867+
&PyEllipsis_Type,
1868+
&PyEnum_Type,
1869+
&PyFrame_Type,
1870+
&PyFrozenSet_Type,
1871+
&PyFunction_Type,
1872+
&PyGen_Type,
1873+
&PyGetSetDescr_Type,
1874+
&PyInstanceMethod_Type,
1875+
&PyListIter_Type,
1876+
&PyListRevIter_Type,
1877+
&PyList_Type,
1878+
&PyLongRangeIter_Type,
1879+
&PyMemberDescr_Type,
1880+
&PyMemoryView_Type,
1881+
&PyMethodDescr_Type,
1882+
&PyMethod_Type,
1883+
&PyModuleDef_Type,
1884+
&PyModule_Type,
1885+
&PyODictIter_Type,
1886+
&PyPickleBuffer_Type,
1887+
&PyProperty_Type,
1888+
&PyRangeIter_Type,
1889+
&PyRange_Type,
1890+
&PyReversed_Type,
1891+
&PySTEntry_Type,
1892+
&PySeqIter_Type,
1893+
&PySetIter_Type,
1894+
&PySet_Type,
1895+
&PySlice_Type,
1896+
&PyStaticMethod_Type,
1897+
&PyStdPrinter_Type,
1898+
&PySuper_Type,
1899+
&PyTraceBack_Type,
1900+
&PyWrapperDescr_Type,
1901+
&Py_GenericAliasType,
1902+
&_PyAnextAwaitable_Type,
1903+
&_PyAsyncGenASend_Type,
1904+
&_PyAsyncGenAThrow_Type,
1905+
&_PyAsyncGenWrappedValue_Type,
1906+
&_PyCoroWrapper_Type,
1907+
&_PyInterpreterID_Type,
1908+
&_PyManagedBuffer_Type,
1909+
&_PyMethodWrapper_Type,
1910+
&_PyNamespace_Type,
1911+
&_PyNone_Type,
1912+
&_PyNotImplemented_Type,
1913+
&_PyUnion_Type,
1914+
&_PyWeakref_CallableProxyType,
1915+
&_PyWeakref_ProxyType,
1916+
&_PyWeakref_RefType,
1917+
1918+
// subclasses: _PyTypes_FiniTypes() deallocates them before their base
1919+
// class
1920+
&PyCMethod_Type, // base=&PyCFunction_Type
1921+
&PyODictItems_Type, // base=&PyDictItems_Type
1922+
&PyODictKeys_Type, // base=&PyDictKeys_Type
1923+
&PyODictValues_Type, // base=&PyDictValues_Type
1924+
&PyODict_Type, // base=&PyDict_Type
1925+
};
1926+
1927+
18401928
PyStatus
18411929
_PyTypes_InitTypes(PyInterpreterState *interp)
18421930
{
@@ -1858,91 +1946,44 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
18581946
assert(PyType_Type.tp_base == &PyBaseObject_Type);
18591947

18601948
// All other static types (unless initialized elsewhere)
1861-
INIT_TYPE(PyAsyncGen_Type);
1862-
INIT_TYPE(PyBool_Type);
1863-
INIT_TYPE(PyByteArrayIter_Type);
1864-
INIT_TYPE(PyByteArray_Type);
1865-
INIT_TYPE(PyCFunction_Type);
1866-
INIT_TYPE(PyCMethod_Type);
1867-
INIT_TYPE(PyCallIter_Type);
1868-
INIT_TYPE(PyCapsule_Type);
1869-
INIT_TYPE(PyCell_Type);
1870-
INIT_TYPE(PyClassMethodDescr_Type);
1871-
INIT_TYPE(PyClassMethod_Type);
1872-
INIT_TYPE(PyCode_Type);
1873-
INIT_TYPE(PyComplex_Type);
1874-
INIT_TYPE(PyCoro_Type);
1875-
INIT_TYPE(PyDictItems_Type);
1876-
INIT_TYPE(PyDictIterItem_Type);
1877-
INIT_TYPE(PyDictIterKey_Type);
1878-
INIT_TYPE(PyDictIterValue_Type);
1879-
INIT_TYPE(PyDictKeys_Type);
1880-
INIT_TYPE(PyDictProxy_Type);
1881-
INIT_TYPE(PyDictRevIterItem_Type);
1882-
INIT_TYPE(PyDictRevIterKey_Type);
1883-
INIT_TYPE(PyDictRevIterValue_Type);
1884-
INIT_TYPE(PyDictValues_Type);
1885-
INIT_TYPE(PyDict_Type);
1886-
INIT_TYPE(PyEllipsis_Type);
1887-
INIT_TYPE(PyEnum_Type);
1888-
INIT_TYPE(PyFrame_Type);
1889-
INIT_TYPE(PyFrozenSet_Type);
1890-
INIT_TYPE(PyFunction_Type);
1891-
INIT_TYPE(PyGen_Type);
1892-
INIT_TYPE(PyGetSetDescr_Type);
1893-
INIT_TYPE(PyInstanceMethod_Type);
1894-
INIT_TYPE(PyListIter_Type);
1895-
INIT_TYPE(PyListRevIter_Type);
1896-
INIT_TYPE(PyList_Type);
1897-
INIT_TYPE(PyLongRangeIter_Type);
1898-
INIT_TYPE(PyMemberDescr_Type);
1899-
INIT_TYPE(PyMemoryView_Type);
1900-
INIT_TYPE(PyMethodDescr_Type);
1901-
INIT_TYPE(PyMethod_Type);
1902-
INIT_TYPE(PyModuleDef_Type);
1903-
INIT_TYPE(PyModule_Type);
1904-
INIT_TYPE(PyODictItems_Type);
1905-
INIT_TYPE(PyODictIter_Type);
1906-
INIT_TYPE(PyODictKeys_Type);
1907-
INIT_TYPE(PyODictValues_Type);
1908-
INIT_TYPE(PyODict_Type);
1909-
INIT_TYPE(PyPickleBuffer_Type);
1910-
INIT_TYPE(PyProperty_Type);
1911-
INIT_TYPE(PyRangeIter_Type);
1912-
INIT_TYPE(PyRange_Type);
1913-
INIT_TYPE(PyReversed_Type);
1914-
INIT_TYPE(PySTEntry_Type);
1915-
INIT_TYPE(PySeqIter_Type);
1916-
INIT_TYPE(PySetIter_Type);
1917-
INIT_TYPE(PySet_Type);
1918-
INIT_TYPE(PySlice_Type);
1919-
INIT_TYPE(PyStaticMethod_Type);
1920-
INIT_TYPE(PyStdPrinter_Type);
1921-
INIT_TYPE(PySuper_Type);
1922-
INIT_TYPE(PyTraceBack_Type);
1923-
INIT_TYPE(PyWrapperDescr_Type);
1924-
INIT_TYPE(Py_GenericAliasType);
1925-
INIT_TYPE(_PyAnextAwaitable_Type);
1926-
INIT_TYPE(_PyAsyncGenASend_Type);
1927-
INIT_TYPE(_PyAsyncGenAThrow_Type);
1928-
INIT_TYPE(_PyAsyncGenWrappedValue_Type);
1929-
INIT_TYPE(_PyCoroWrapper_Type);
1930-
INIT_TYPE(_PyInterpreterID_Type);
1931-
INIT_TYPE(_PyManagedBuffer_Type);
1932-
INIT_TYPE(_PyMethodWrapper_Type);
1933-
INIT_TYPE(_PyNamespace_Type);
1934-
INIT_TYPE(_PyNone_Type);
1935-
INIT_TYPE(_PyNotImplemented_Type);
1936-
INIT_TYPE(_PyWeakref_CallableProxyType);
1937-
INIT_TYPE(_PyWeakref_ProxyType);
1938-
INIT_TYPE(_PyWeakref_RefType);
1939-
INIT_TYPE(_PyUnion_Type);
1949+
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
1950+
PyTypeObject *type = static_types[i];
1951+
if (PyType_Ready(type) < 0) {
1952+
return _PyStatus_ERR("Can't initialize types");
1953+
}
1954+
}
19401955

19411956
return _PyStatus_OK();
19421957
#undef INIT_TYPE
19431958
}
19441959

19451960

1961+
// Best-effort function clearing static types.
1962+
//
1963+
// Don't deallocate a type if it still has subclasses. If a Py_Finalize()
1964+
// sub-function is interrupted by CTRL+C or fails with MemoryError, some
1965+
// subclasses are not cleared properly. Leave the static type unchanged in this
1966+
// case.
1967+
void
1968+
_PyTypes_FiniTypes(PyInterpreterState *interp)
1969+
{
1970+
if (!_Py_IsMainInterpreter(interp)) {
1971+
return;
1972+
}
1973+
1974+
// Deallocate types in the reverse order to deallocate subclasses before
1975+
// their base classes.
1976+
for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) {
1977+
PyTypeObject *type = static_types[i];
1978+
// Cannot delete a type if it still has subclasses
1979+
if (type->tp_subclasses != NULL) {
1980+
continue;
1981+
}
1982+
_PyStaticType_Dealloc(type);
1983+
}
1984+
}
1985+
1986+
19461987
void
19471988
_Py_NewReference(PyObject *op)
19481989
{

Objects/typeobject.c

+22-6
Original file line numberDiff line numberDiff line change
@@ -4071,6 +4071,18 @@ extern void
40714071
_PyDictKeys_DecRef(PyDictKeysObject *keys);
40724072

40734073

4074+
static void
4075+
type_dealloc_common(PyTypeObject *type)
4076+
{
4077+
PyObject *tp, *val, *tb;
4078+
PyErr_Fetch(&tp, &val, &tb);
4079+
remove_all_subclasses(type, type->tp_bases);
4080+
PyErr_Restore(tp, val, tb);
4081+
4082+
PyObject_ClearWeakRefs((PyObject *)type);
4083+
}
4084+
4085+
40744086
void
40754087
_PyStaticType_Dealloc(PyTypeObject *type)
40764088
{
@@ -4079,34 +4091,34 @@ _PyStaticType_Dealloc(PyTypeObject *type)
40794091
// and a type must no longer be used once it's deallocated.
40804092
assert(type->tp_subclasses == NULL);
40814093

4094+
type_dealloc_common(type);
4095+
40824096
Py_CLEAR(type->tp_dict);
40834097
Py_CLEAR(type->tp_bases);
40844098
Py_CLEAR(type->tp_mro);
40854099
Py_CLEAR(type->tp_cache);
40864100
Py_CLEAR(type->tp_subclasses);
4101+
40874102
type->tp_flags &= ~Py_TPFLAGS_READY;
40884103
}
40894104

40904105

40914106
static void
40924107
type_dealloc(PyTypeObject *type)
40934108
{
4094-
PyObject *tp, *val, *tb;
4095-
40964109
/* Assert this is a heap-allocated type object */
40974110
_PyObject_ASSERT((PyObject *)type, type->tp_flags & Py_TPFLAGS_HEAPTYPE);
40984111
_PyObject_GC_UNTRACK(type);
4099-
PyErr_Fetch(&tp, &val, &tb);
4100-
remove_all_subclasses(type, type->tp_bases);
4101-
PyErr_Restore(tp, val, tb);
41024112

4103-
PyObject_ClearWeakRefs((PyObject *)type);
4113+
type_dealloc_common(type);
4114+
41044115
Py_XDECREF(type->tp_base);
41054116
Py_XDECREF(type->tp_dict);
41064117
Py_XDECREF(type->tp_bases);
41074118
Py_XDECREF(type->tp_mro);
41084119
Py_XDECREF(type->tp_cache);
41094120
Py_XDECREF(type->tp_subclasses);
4121+
41104122
/* A type's tp_doc is heap allocated, unlike the tp_doc slots
41114123
* of most other objects. It's okay to cast it to char *.
41124124
*/
@@ -6541,6 +6553,10 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type)
65416553
PyErr_Clear();
65426554
}
65436555
Py_XDECREF(key);
6556+
6557+
if (PyDict_Size(dict) == 0) {
6558+
Py_CLEAR(base->tp_subclasses);
6559+
}
65446560
}
65456561

65466562
static void

Python/pylifecycle.c

+1
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,7 @@ finalize_interp_types(PyInterpreterState *interp)
16761676
_PyThread_FiniType(interp);
16771677
_PyErr_FiniTypes(interp);
16781678
_PyTypes_Fini(interp);
1679+
_PyTypes_FiniTypes(interp);
16791680

16801681
// Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses
16811682
// a dict internally.

0 commit comments

Comments
 (0)