[Python-checkins] cpython (merge 3.5 -> 3.6): merge 3.5 (#26617)

benjamin.peterson python-checkins at python.org
Tue Oct 4 03:01:19 EDT 2016


https://hg.python.org/cpython/rev/520cb70ecb90
changeset:   104272:520cb70ecb90
branch:      3.6
parent:      104265:de79cc895203
parent:      104271:c9b7272e2553
user:        Benjamin Peterson <benjamin at python.org>
date:        Tue Oct 04 00:00:23 2016 -0700
summary:
  merge 3.5 (#26617)

files:
  Lib/test/test_weakref.py |   8 ++++++++
  Misc/NEWS                |   2 ++
  Objects/typeobject.c     |  27 ++++++++++++++-------------
  3 files changed, 24 insertions(+), 13 deletions(-)


diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -845,6 +845,14 @@
         with self.assertRaises(AttributeError):
             ref1.__callback__ = lambda ref: None
 
+    def test_callback_gcs(self):
+        class ObjectWithDel(Object):
+            def __del__(self): pass
+        x = ObjectWithDel(1)
+        ref1 = weakref.ref(x, lambda ref: support.gc_collect())
+        del x
+        support.gc_collect()
+
 
 class SubclassableWeakrefTestCase(TestBase):
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@
 Core and Builtins
 -----------------
 
+- Issue #26617: Fix crash when GC runs during weakref callbacks.
+
 - Issue #27942: String constants now interned recursively in tuples and frozensets.
 
 - Issue #21578: Fixed misleading error message when ImportError called with
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1136,11 +1136,6 @@
     Py_TRASHCAN_SAFE_BEGIN(self);
     --_PyTrash_delete_nesting;
     -- tstate->trash_delete_nesting;
-    /* DO NOT restore GC tracking at this point.  weakref callbacks
-     * (if any, and whether directly here or indirectly in something we
-     * call) may trigger GC, and if self is tracked at that point, it
-     * will look like trash to GC and GC will try to delete self again.
-     */
 
     /* Find the nearest base with a different tp_dealloc */
     base = type;
@@ -1151,30 +1146,36 @@
 
     has_finalizer = type->tp_finalize || type->tp_del;
 
-    /* Maybe call finalizer; exit early if resurrected */
-    if (has_finalizer)
+    if (type->tp_finalize) {
         _PyObject_GC_TRACK(self);
-
-    if (type->tp_finalize) {
         if (PyObject_CallFinalizerFromDealloc(self) < 0) {
             /* Resurrected */
             goto endlabel;
         }
-    }
-    /* If we added a weaklist, we clear it.      Do this *before* calling
-       tp_del, clearing slots, or clearing the instance dict. */
+        _PyObject_GC_UNTRACK(self);
+    }
+    /*
+      If we added a weaklist, we clear it. Do this *before* calling tp_del,
+      clearing slots, or clearing the instance dict.
+
+      GC tracking must be off at this point. weakref callbacks (if any, and
+      whether directly here or indirectly in something we call) may trigger GC,
+      and if self is tracked at that point, it will look like trash to GC and GC
+      will try to delete self again.
+    */
     if (type->tp_weaklistoffset && !base->tp_weaklistoffset)
         PyObject_ClearWeakRefs(self);
 
     if (type->tp_del) {
+        _PyObject_GC_TRACK(self);
         type->tp_del(self);
         if (self->ob_refcnt > 0) {
             /* Resurrected */
             goto endlabel;
         }
+        _PyObject_GC_UNTRACK(self);
     }
     if (has_finalizer) {
-        _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

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list