diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-19-16-10-44.bpo-41036.QO7L7f.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-19-16-10-44.bpo-41036.QO7L7f.rst new file mode 100644 index 00000000000000..a42ed7f5450731 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-19-16-10-44.bpo-41036.QO7L7f.rst @@ -0,0 +1,3 @@ +Provide a default tp_traverse implementation for the base object type for +heap types which have no tp_traverse function. The traverse function visits +the type if the type is a heap type. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f0e349ecd2bb92..35db98a0574a1f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1139,8 +1139,10 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg) Py_VISIT(type); } - if (basetraverse) + // Don't call object_traverse() to avoid visiting the type twice + if (basetraverse && base != &PyBaseObject_Type) { return basetraverse(self, visit, arg); + } return 0; } @@ -4906,6 +4908,18 @@ object___dir___impl(PyObject *self) return result; } +static int +object_traverse(PyObject *op, visitproc visit, void *arg) +{ + PyTypeObject *type = Py_TYPE(op); + if (_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { + // For instance of heap types, tp_type is a strong reference + // to the type. + Py_VISIT(type); + } + return 0; +} + static PyMethodDef object_methods[] = { OBJECT___REDUCE_EX___METHODDEF OBJECT___REDUCE___METHODDEF @@ -4947,7 +4961,7 @@ PyTypeObject PyBaseObject_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ object_doc, /* tp_doc */ - 0, /* tp_traverse */ + object_traverse, /* tp_traverse */ 0, /* tp_clear */ object_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */