mirror of
https://github.com/python/cpython.git
synced 2025-08-22 01:35:16 +00:00
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
5 changed files with 33 additions and 1 deletions
|
@ -1,11 +1,12 @@
|
||||||
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
|
||||||
|
|
||||||
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):
|
||||||
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?
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue