Fix SF bug 574207 (chained __slots__ dealloc segfault).

This is inspired by SF patch 581742 (by Jonathan Hogg, who also
submitted the bug report, and two other suggested patches), but
separates the non-GC case from the GC case to avoid testing for GC
several times.

Had to fix an assert() from call_finalizer() that asserted that the
object wasn't untracked, because it's possible that the object isn't
GC'ed!
This commit is contained in:
Guido van Rossum 2002-08-06 21:41:44 +00:00
parent 31f3db39f3
commit 22b1387c51
1 changed files with 52 additions and 10 deletions

View File

@ -401,7 +401,8 @@ call_finalizer(PyObject *self)
_Py_NewReference(self);
self->ob_refcnt = refcnt;
}
assert(_Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
assert(!PyType_IS_GC(self->ob_type) ||
_Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
/* If Py_REF_DEBUG, the original decref dropped _Py_RefTotal, but
* _Py_NewReference bumped it again, so that's a wash.
* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
@ -423,14 +424,55 @@ subtype_dealloc(PyObject *self)
PyTypeObject *type, *base;
destructor basedealloc;
/* This exists so we can DECREF self->ob_type */
/* Extract the type; we expect it to be a heap type */
type = self->ob_type;
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
/* Test whether the type has GC exactly once */
if (!PyType_IS_GC(type)) {
/* It's really rare to find a dynamic type that doesn't have
GC; it can only happen when deriving from 'object' and not
adding any slots or instance variables. This allows
certain simplifications: there's no need to call
clear_slots(), or DECREF the dict, or clear weakrefs. */
/* Maybe call finalizer; exit early if resurrected */
if (call_finalizer(self) < 0)
return;
/* Find the nearest base with a different tp_dealloc */
base = type;
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
assert(base->ob_size == 0);
base = base->tp_base;
assert(base);
}
/* Call the base tp_dealloc() */
assert(basedealloc);
basedealloc(self);
/* Can't reference self beyond this point */
Py_DECREF(type);
/* Done */
return;
}
/* We get here only if the type has GC */
/* UnTrack and re-Track around the trashcan macro, alas */
_PyObject_GC_UNTRACK(self);
Py_TRASHCAN_SAFE_BEGIN(self);
_PyObject_GC_TRACK(self); /* We'll untrack for real later */
/* Maybe call finalizer; exit early if resurrected */
if (call_finalizer(self) < 0)
return;
/* Find the nearest base with a different tp_dealloc
and clear slots while we're at it */
type = self->ob_type;
base = type;
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
if (base->ob_size)
@ -456,7 +498,7 @@ subtype_dealloc(PyObject *self)
PyObject_ClearWeakRefs(self);
/* Finalize GC if the base doesn't do GC and we do */
if (PyType_IS_GC(type) && !PyType_IS_GC(base))
if (!PyType_IS_GC(base))
_PyObject_GC_UNTRACK(self);
/* Call the base tp_dealloc() */
@ -464,9 +506,9 @@ subtype_dealloc(PyObject *self)
basedealloc(self);
/* Can't reference self beyond this point */
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
Py_DECREF(type);
}
Py_TRASHCAN_SAFE_END(self);
}
static PyTypeObject *solid_base(PyTypeObject *type);