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
(!type->tp_traverse && !type->tp_clear)) {
(!type->tp_traverse || !type->tp_clear)) {
Don't know what to do. Maybe we should only update the doc.