mirror of https://github.com/python/cpython.git
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:
parent
31f3db39f3
commit
22b1387c51
|
@ -401,7 +401,8 @@ call_finalizer(PyObject *self)
|
||||||
_Py_NewReference(self);
|
_Py_NewReference(self);
|
||||||
self->ob_refcnt = refcnt;
|
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
|
/* If Py_REF_DEBUG, the original decref dropped _Py_RefTotal, but
|
||||||
* _Py_NewReference bumped it again, so that's a wash.
|
* _Py_NewReference bumped it again, so that's a wash.
|
||||||
* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
|
* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
|
||||||
|
@ -423,14 +424,55 @@ subtype_dealloc(PyObject *self)
|
||||||
PyTypeObject *type, *base;
|
PyTypeObject *type, *base;
|
||||||
destructor basedealloc;
|
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)
|
if (call_finalizer(self) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Find the nearest base with a different tp_dealloc
|
/* Find the nearest base with a different tp_dealloc
|
||||||
and clear slots while we're at it */
|
and clear slots while we're at it */
|
||||||
type = self->ob_type;
|
|
||||||
base = type;
|
base = type;
|
||||||
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
|
while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
|
||||||
if (base->ob_size)
|
if (base->ob_size)
|
||||||
|
@ -456,7 +498,7 @@ subtype_dealloc(PyObject *self)
|
||||||
PyObject_ClearWeakRefs(self);
|
PyObject_ClearWeakRefs(self);
|
||||||
|
|
||||||
/* Finalize GC if the base doesn't do GC and we do */
|
/* 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);
|
_PyObject_GC_UNTRACK(self);
|
||||||
|
|
||||||
/* Call the base tp_dealloc() */
|
/* Call the base tp_dealloc() */
|
||||||
|
@ -464,9 +506,9 @@ subtype_dealloc(PyObject *self)
|
||||||
basedealloc(self);
|
basedealloc(self);
|
||||||
|
|
||||||
/* Can't reference self beyond this point */
|
/* Can't reference self beyond this point */
|
||||||
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
|
Py_DECREF(type);
|
||||||
Py_DECREF(type);
|
|
||||||
}
|
Py_TRASHCAN_SAFE_END(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyTypeObject *solid_base(PyTypeObject *type);
|
static PyTypeObject *solid_base(PyTypeObject *type);
|
||||||
|
|
Loading…
Reference in New Issue