]> granicus.if.org Git - python/commitdiff
If you created a weakref in an object's __del__ method to itself it would
authorBrett Cannon <bcannon@gmail.com>
Tue, 23 Jan 2007 22:41:20 +0000 (22:41 +0000)
committerBrett Cannon <bcannon@gmail.com>
Tue, 23 Jan 2007 22:41:20 +0000 (22:41 +0000)
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.

Lib/test/crashers/weakref_in_del.py
Lib/test/test_weakref.py
Misc/NEWS
Objects/typeobject.c
Objects/weakrefobject.c

index 3bbcfc3efdcb69677a4094ef6c824912b6762c34..2e9b186837497a1cfee726713bd230328c3f765e 100644 (file)
@@ -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)
index 18ab4012fb7f57fba0aedc1f0595950e8c8a79f5..c669109f08b221f676610f70adbc2a848b21ff36 100644 (file)
@@ -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):
 
index fc5dd66f0dc3910a8574b654871c69ab1f3449c9..fccc50df5f5b50343d28299430e5921c3f1c5b7b 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index d4a46c37f02e122dca5a31b0f62cbb824f4de3c1..a8395ef9b23546f0e7a55276d787ab0795e3ce64 100644 (file)
@@ -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 */
index 826f5710dcf37f7a89482a88f79b037887126eaf..a404f29ade2b0bdeb00b4f3abaa32384806b3437 100644 (file)
@@ -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)