Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 595225e

Browse filesBrowse 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
Copy full SHA for 595225e

File tree

4 files changed

+144
-85
lines changed
Filter options

4 files changed

+144
-85
lines changed

‎Include/internal/pycore_typeobject.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_typeobject.h
+1Lines changed: 1 addition & 0 deletions
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

Copy file name to clipboardExpand all lines: Objects/object.c
+120-79Lines changed: 120 additions & 79 deletions
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

Copy file name to clipboardExpand all lines: Objects/typeobject.c
+22-6Lines changed: 22 additions & 6 deletions
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

Copy file name to clipboardExpand all lines: Python/pylifecycle.c
+1Lines changed: 1 addition & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.