Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f5bee30

Browse files
committed
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.
1 parent 6c5c502 commit f5bee30

5 files changed

Lines changed: 34 additions & 1 deletion

File tree

Lib/test/crashers/weakref_in_del.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import weakref
22

33
# http://python.org/sf/1377858
4+
# Fixed for new-style classes in 2.5c1.
45

56
ref = None
67

78
def test_weakref_in_del():
8-
class Target(object):
9+
class Target():
910
def __del__(self):
1011
global ref
1112
ref = weakref.ref(self)

Lib/test/test_weakref.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from test import test_support
88

9+
# Used in ReferencesTestCase.test_ref_created_during_del() .
10+
ref_from_del = None
911

1012
class C:
1113
def method(self):
@@ -630,6 +632,18 @@ def callback(*args):
630632
finally:
631633
gc.set_threshold(*thresholds)
632634

635+
def test_ref_created_during_del(self):
636+
# Bug #1377858
637+
# A weakref created in an object's __del__() would crash the
638+
# interpreter when the weakref was cleaned up since it would refer to
639+
# non-existent memory. This test should not segfault the interpreter.
640+
class Target(object):
641+
def __del__(self):
642+
global ref_from_del
643+
ref_from_del = weakref.ref(self)
644+
645+
w = Target()
646+
633647

634648
class SubclassableWeakrefTestCase(unittest.TestCase):
635649

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
1212
Core and builtins
1313
-----------------
1414

15+
- Bug #1377858: Fix the segfaulting of the interpreter when an object created
16+
a weakref on itself during a __del__ call for new-style classes (classic
17+
classes still have the bug).
18+
1519
- Bug #1579370: Make PyTraceBack_Here use the current thread, not the
1620
frame's thread state.
1721

Objects/typeobject.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,17 @@ subtype_dealloc(PyObject *self)
666666
goto endlabel; /* resurrected */
667667
else
668668
_PyObject_GC_UNTRACK(self);
669+
/* New weakrefs could be created during the finalizer call.
670+
If this occurs, clear them out without calling their
671+
finalizers since they might rely on part of the object
672+
being finalized that has already been destroyed. */
673+
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
674+
/* Modeled after GET_WEAKREFS_LISTPTR() */
675+
PyWeakReference **list = (PyWeakReference **) \
676+
PyObject_GET_WEAKREFS_LISTPTR(self);
677+
while (*list)
678+
_PyWeakref_ClearRef(*list);
679+
}
669680
}
670681

671682
/* Clear slots up to the nearest base with a different tp_dealloc */

Objects/weakrefobject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ clear_weakref(PyWeakReference *self)
5757
PyWeakref_GET_OBJECT(self));
5858

5959
if (*list == self)
60+
/* If 'self' is the end of the list (and thus self->wr_next == NULL)
61+
then the weakref list itself (and thus the value of *list) will
62+
end up being set to NULL. */
6063
*list = self->wr_next;
6164
self->wr_object = Py_None;
6265
if (self->wr_prev != NULL)

0 commit comments

Comments
 (0)