From ba2958ed40d284228836735cbed4a155190e0998 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 11 Nov 2020 14:27:32 +0100 Subject: [PATCH] bpo-40170: Fix PyType_Ready() refleak on static type (GH-23236) bpo-1635741, bpo-40170: When called on a static type with NULL tp_base, PyType_Ready() no longer increments the reference count of the PyBaseObject_Type ("object). PyTypeObject.tp_base is a strong reference on a heap type, but it is borrowed reference on a static type. Fix 99 reference leaks at Python exit (showrefcount 18623 => 18524). --- Include/cpython/object.h | 1 + Objects/typeobject.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index ec6a3647677..43b0be37557 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -244,6 +244,7 @@ struct _typeobject { struct PyMethodDef *tp_methods; struct PyMemberDef *tp_members; struct PyGetSetDef *tp_getset; + // Strong reference on a heap type, borrowed reference on a static type struct _typeobject *tp_base; PyObject *tp_dict; descrgetfunc tp_descr_get; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4d0a3faeceb..fd018b8b032 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5487,8 +5487,13 @@ PyType_Ready(PyTypeObject *type) /* Initialize tp_base (defaults to BaseObject unless that's us) */ base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { - base = type->tp_base = &PyBaseObject_Type; - Py_INCREF(base); + base = &PyBaseObject_Type; + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { + type->tp_base = (PyTypeObject*)Py_NewRef((PyObject*)base); + } + else { + type->tp_base = base; + } } /* Now the only way base can still be NULL is if type is