Commit f5bee30e authored by Brett Cannon's avatar Brett Cannon

Fix crasher for when an object's __del__ creates a new weakref to itself.

Patch only fixes new-style classes; classic classes still buggy.

Closes bug #1377858.  Already backported.
parent 6c5c502b
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,10 @@ What's New in Python 2.6 alpha 1?
Core and builtins
-----------------
- Bug #1377858: Fix the segfaulting of the interpreter when an object created
a weakref on itself during a __del__ call for new-style classes (classic
classes still have the bug).
- 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)
......
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