diff options
author | Guido van Rossum <guido@python.org> | 2002-08-07 20:42:09 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2002-08-07 20:42:09 (GMT) |
commit | 0906e074426fc596cffb157e28be4bf82de62c7b (patch) | |
tree | e71bd0184a559a446398c68d9227152d5600e3a1 | |
parent | ae7ef57cba593d6c7eee8d1fd887c98a135770b3 (diff) | |
download | cpython-0906e074426fc596cffb157e28be4bf82de62c7b.zip cpython-0906e074426fc596cffb157e28be4bf82de62c7b.tar.gz cpython-0906e074426fc596cffb157e28be4bf82de62c7b.tar.bz2 |
Fix a subtle bug in the trashcan code I added yesterday to
subtype_dealloc().
When call_finalizer() failed, it would return without going through
the trashcan end macro, thereby unbalancing the trashcan nesting level
counter, and thereby defeating the test case (slottrash() in
test_descr.py). This in turn meant that the assert in the GC_UNTRACK
macro wasn't triggered by the slottrash() test despite a bug in the
code: _PyTrash_destroy_chain() calls the dealloc routine with an
object that's untracked, and the assert in the GC_UNTRACK macro would
fail on this; but because of an earlier test that resurrects an
object, causing call_finalizer() to fail and the trashcan nesting
level to be unbalanced, so _PyTrash_destroy_chain() was never called.
Calling the slottrash() test in isolation *did* trigger the assert,
however.
So the fix is twofold: (1) call the GC_UnTrack() function instead of
the GC_UNTRACK macro, because the function is safe when the object is
already untracked; (2) when call_finalizer() fails, jump to a label
that exits through the trashcan end macro, keeping the trashcan
nesting balanced.
-rw-r--r-- | Objects/typeobject.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b7edb14..d494344 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -463,13 +463,13 @@ subtype_dealloc(PyObject *self) /* We get here only if the type has GC */ /* UnTrack and re-Track around the trashcan macro, alas */ - _PyObject_GC_UNTRACK(self); + 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; + goto endlabel; /* Find the nearest base with a different tp_dealloc and clear slots while we're at it */ @@ -508,6 +508,7 @@ subtype_dealloc(PyObject *self) /* Can't reference self beyond this point */ Py_DECREF(type); + endlabel: Py_TRASHCAN_SAFE_END(self); } |