Commit e6950b8c authored by Brett Cannon's avatar Brett Cannon

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.
parent d4e5f0ad
import weakref import weakref
# http://python.org/sf/1377858 # http://python.org/sf/1377858
# Fixed for new-style classes in 2.5c1.
ref = None ref = None
def test_weakref_in_del(): def test_weakref_in_del():
class Target(object): class Target():
def __del__(self): def __del__(self):
global ref global ref
ref = weakref.ref(self) ref = weakref.ref(self)
......
...@@ -6,6 +6,8 @@ import weakref ...@@ -6,6 +6,8 @@ import weakref
from test import test_support from test import test_support
# Used in ReferencesTestCase.test_ref_created_during_del() .
ref_from_del = None
class C: class C:
def method(self): def method(self):
...@@ -630,6 +632,18 @@ class ReferencesTestCase(TestBase): ...@@ -630,6 +632,18 @@ class ReferencesTestCase(TestBase):
finally: finally:
gc.set_threshold(*thresholds) 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): class SubclassableWeakrefTestCase(unittest.TestCase):
......
...@@ -12,6 +12,9 @@ What's New in Python 2.5.1c1? ...@@ -12,6 +12,9 @@ What's New in Python 2.5.1c1?
Core and builtins 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 - Bug #1579370: Make PyTraceBack_Here use the current thread, not the
frame's thread state. frame's thread state.
......
...@@ -666,6 +666,17 @@ subtype_dealloc(PyObject *self) ...@@ -666,6 +666,17 @@ subtype_dealloc(PyObject *self)
goto endlabel; /* resurrected */ goto endlabel; /* resurrected */
else else
_PyObject_GC_UNTRACK(self); _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 */ /* Clear slots up to the nearest base with a different tp_dealloc */
......
...@@ -57,6 +57,9 @@ clear_weakref(PyWeakReference *self) ...@@ -57,6 +57,9 @@ clear_weakref(PyWeakReference *self)
PyWeakref_GET_OBJECT(self)); PyWeakref_GET_OBJECT(self));
if (*list == 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; *list = self->wr_next;
self->wr_object = Py_None; self->wr_object = Py_None;
if (self->wr_prev != NULL) if (self->wr_prev != NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment