If you created a weakref in an object's __del__ method to itself it would

segfault the interpreter during weakref clean up.  Now any new weakrefs created
after __del__ is run are removed silently.

Fixes bug #1377858 and the weakref_in_del crasher for new-style classes.
Classic classes are still affected.
This commit is contained in:
Brett Cannon 2007-01-23 22:41:20 +00:00
parent 601d03a5be
commit 75ba075110
5 changed files with 33 additions and 1 deletions

View File

@ -1,11 +1,12 @@
import weakref
# http://python.org/sf/1377858
# Fixed for new-style classes in 2.5c1.
ref = None
def test_weakref_in_del():
class Target(object):
class Target():
def __del__(self):
global ref
ref = weakref.ref(self)

View File

@ -6,6 +6,8 @@ import weakref
from test import test_support
# Used in ReferencesTestCase.test_ref_created_during_del() .
ref_from_del = None
class C:
def method(self):
@ -630,6 +632,18 @@ class ReferencesTestCase(TestBase):
finally:
gc.set_threshold(*thresholds)
def test_ref_created_during_del(self):
# Bug #1377858
# A weakref created in an object's __del__() would crash the
# interpreter when the weakref was cleaned up since it would refer to
# non-existent memory. This test should not segfault the interpreter.
class Target(object):
def __del__(self):
global ref_from_del
ref_from_del = weakref.ref(self)
w = Target()
class SubclassableWeakrefTestCase(unittest.TestCase):

View File

@ -12,6 +12,9 @@ What's New in Python 2.5.1c1?
Core and builtins
-----------------
- Bug #1377858: Fix the segfaulting of the interpreter when an object created
a weakref on itself during a __del__ call.
- Bug #1579370: Make PyTraceBack_Here use the current thread, not the
frame's thread state.

View File

@ -666,6 +666,17 @@ subtype_dealloc(PyObject *self)
goto endlabel; /* resurrected */
else
_PyObject_GC_UNTRACK(self);
/* New weakrefs could be created during the finalizer call.
If this occurs, clear them out without calling their
finalizers since they might rely on part of the object
being finalized that has already been destroyed. */
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
/* Modeled after GET_WEAKREFS_LISTPTR() */
PyWeakReference **list = (PyWeakReference **) \
PyObject_GET_WEAKREFS_LISTPTR(self);
while (*list)
_PyWeakref_ClearRef(*list);
}
}
/* Clear slots up to the nearest base with a different tp_dealloc */

View File

@ -57,6 +57,9 @@ clear_weakref(PyWeakReference *self)
PyWeakref_GET_OBJECT(self));
if (*list == self)
/* If 'self' is the end of the list (and thus self->wr_next == NULL)
then the weakref list itself (and thus the value of *list) will
end up being set to NULL. */
*list = self->wr_next;
self->wr_object = Py_None;
if (self->wr_prev != NULL)