mirror of
https://github.com/python/cpython.git
synced 2024-11-26 03:14:27 +08:00
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);
|
||||
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_DECREF(type);
|
||||
|
||||
Py_TRASHCAN_SAFE_END(self);
|
||||
}
|
||||
|
||||
static PyTypeObject *solid_base(PyTypeObject *type);
|
||||
@ -2807,7 +2849,7 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped)
|
||||
{
|
||||
@ -2992,7 +3034,7 @@ slot_sq_length(PyObject *self)
|
||||
if (len == -1 && PyErr_Occurred())
|
||||
return -1;
|
||||
if (len < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"__len__() should return >= 0");
|
||||
return -1;
|
||||
}
|
||||
@ -4039,7 +4081,7 @@ update_one_slot(PyTypeObject *type, slotdef *p)
|
||||
return p;
|
||||
}
|
||||
|
||||
static int recurse_down_subclasses(PyTypeObject *type, slotdef **pp,
|
||||
static int recurse_down_subclasses(PyTypeObject *type, slotdef **pp,
|
||||
PyObject *name);
|
||||
|
||||
/* In the type, update the slots whose slotdefs are gathered in the pp0 array,
|
||||
|
Loading…
Reference in New Issue
Block a user