GH-104510: Fix refleaks in _io base types by kumaraditya303 · Pull Request #104516 · python/cpython (original) (raw)

The heap type still has GC but it now inherits traverse and clear slots from its base because Py_TPFLAGS_HAVE_GC isn't set. See https://docs.python.org/3.12/c-api/gcsupport.html

The doc's a bit unclear here.

When calling PyType_Ready() or some of the APIs that indirectly call it like PyType_FromSpecWithBases() or PyType_FromSpec() the interpreter will automatically populate the tp_flags, tp_traverse and tp_clear fields if the type inherits from a class that implements the garbage collector protocol and the child class does not include the Py_TPFLAGS_HAVE_GC flag.

From the code, we see,

if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
(base->tp_flags & Py_TPFLAGS_HAVE_GC) &&
(!type->tp_traverse && !type->tp_clear)) {
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
if (type->tp_traverse == NULL)
type->tp_traverse = base->tp_traverse;
if (type->tp_clear == NULL)
type->tp_clear = base->tp_clear;
}

To get the tp_traverse and tp_clear inherited, the child type must have them both NULL.

This is against the doc. Also, the comparisons in lines 6674 and 6676 are unnecessary.

It was a 22-yr old code 13d52f0. I guess the author (@gvanrossum) was trying to write

Don't know what to do. Maybe we should only update the doc.