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:
parent
601d03a5be
commit
75ba075110
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue