[Python-Dev] Bizarre new test failure
Guido van Rossum
guido@python.org
Sun, 09 Jun 2002 19:15:39 -0400
> > When tp_dict is cleared, this can remove the __del__ method before it
> > can be called (it is called by the instance's tp_dealloc).
>
> That cannot happen: an object whose type has an __del__ cannot refer
> to an object for which tp_clear has been called. Objects with
> finalizers go into gc.garbage, so in this case, the type is
> resurrected, and not cleared.
You're right!
> > tp_mro participates in a cycle too: it is a tuple whose first element
> > is the type itself. Tuples are immutable, so the tp_clear for tuples
> > doesn't do anything. So type_clear is our only hope to break this
> > cycle.
>
> I see. So tp_mro must be cleared in tp_clear; it's not used from
> subtype_dealloc, so it won't cause problems to clear it.
You've convinced me. Here's a patch that only touches typeobject.c.
It doesn't add any fields, and it doesn't require multiple collections
to clear out cycles involving a class and its type. I like it!
(Note: at the top of type_traverse() and type_clear(), there used to
be code saying "if not a heaptype, return". That code was never
necessary, because the collector doesn't call the traverse or clear
hooks when tp_is_gc() returns false -- which it does when the heaptype
flag isn't set. So I replaced these two with an assert that this is a
heaptype.)
Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.148
diff -c -c -r2.148 typeobject.c
*** typeobject.c 4 Jun 2002 19:52:53 -0000 2.148
--- typeobject.c 9 Jun 2002 23:05:47 -0000
***************
*** 290,295 ****
--- 290,301 ----
}
}
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ int err = visit((PyObject *)type, arg);
+ if (err)
+ return err;
+ }
+
if (basetraverse)
return basetraverse(self, visit, arg);
return 0;
***************
*** 1323,1329 ****
return NULL;
}
mro = type->tp_mro;
! assert(mro != NULL);
}
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
--- 1329,1336 ----
return NULL;
}
mro = type->tp_mro;
! if (mro == NULL)
! return NULL;
}
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
***************
*** 1335,1341 ****
assert(PyType_Check(base));
dict = ((PyTypeObject *)base)->tp_dict;
}
! assert(dict && PyDict_Check(dict));
res = PyDict_GetItem(dict, name);
if (res != NULL)
return res;
--- 1342,1349 ----
assert(PyType_Check(base));
dict = ((PyTypeObject *)base)->tp_dict;
}
! if (dict == NULL || !PyDict_Check(dict))
! continue;
res = PyDict_GetItem(dict, name);
if (res != NULL)
return res;
***************
*** 1495,1502 ****
etype *et;
int err;
! if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
! return 0;
et = (etype *)type;
--- 1503,1509 ----
etype *et;
int err;
! assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
et = (etype *)type;
***************
*** 1512,1519 ****
VISIT(type->tp_mro);
VISIT(type->tp_bases);
VISIT(type->tp_base);
- VISIT(type->tp_subclasses);
- VISIT(et->slots);
#undef VISIT
--- 1519,1524 ----
***************
*** 1526,1533 ****
etype *et;
PyObject *tmp;
! if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
! return 0;
et = (etype *)type;
--- 1531,1537 ----
etype *et;
PyObject *tmp;
! assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
et = (etype *)type;
***************
*** 1541,1555 ****
CLEAR(type->tp_dict);
CLEAR(type->tp_cache);
CLEAR(type->tp_mro);
- CLEAR(type->tp_bases);
- CLEAR(type->tp_base);
- CLEAR(type->tp_subclasses);
- CLEAR(et->slots);
-
- if (type->tp_doc != NULL) {
- PyObject_FREE(type->tp_doc);
- type->tp_doc = NULL;
- }
#undef CLEAR
--- 1545,1550 ----
***************
*** 2166,2175 ****
PyTypeObject *base;
int i, n;
! if (type->tp_flags & Py_TPFLAGS_READY) {
! assert(type->tp_dict != NULL);
return 0;
- }
assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);
type->tp_flags |= Py_TPFLAGS_READYING;
--- 2161,2168 ----
PyTypeObject *base;
int i, n;
! if (type->tp_flags & Py_TPFLAGS_READY)
return 0;
assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);
type->tp_flags |= Py_TPFLAGS_READYING;
--Guido van Rossum (home page: http://www.python.org/~guido/)