[Python-checkins] cpython (2.7): allow cycles throught the __dict__ slot to be cleared (closes #1469629)

benjamin.peterson python-checkins at python.org
Thu Mar 8 02:15:36 CET 2012


http://hg.python.org/cpython/rev/c7623da4e2af
changeset:   75487:c7623da4e2af
branch:      2.7
parent:      75472:077b42a54803
user:        Benjamin Peterson <benjamin at python.org>
date:        Wed Mar 07 18:41:11 2012 -0600
summary:
  allow cycles throught the __dict__ slot to be cleared (closes #1469629)

Patch from Armin, test from me.

files:
  Lib/test/test_descr.py |  19 +++++++++++++++++--
  Misc/NEWS              |   3 +++
  Objects/typeobject.c   |   9 +++++++--
  3 files changed, 27 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1,7 +1,9 @@
 import __builtin__
+import gc
 import sys
 import types
 import unittest
+import weakref
 
 from copy import deepcopy
 from test import test_support
@@ -1127,7 +1129,6 @@
         self.assertEqual(Counted.counter, 0)
 
         # Test lookup leaks [SF bug 572567]
-        import gc
         if hasattr(gc, 'get_objects'):
             class G(object):
                 def __cmp__(self, other):
@@ -4541,7 +4542,6 @@
         self.assertRaises(AttributeError, getattr, C(), "attr")
         self.assertEqual(descr.counter, 4)
 
-        import gc
         class EvilGetattribute(object):
             # This used to segfault
             def __getattr__(self, name):
@@ -4590,6 +4590,21 @@
         foo = Foo()
         str(foo)
 
+    def test_cycle_through_dict(self):
+        # See bug #1469629
+        class X(dict):
+            def __init__(self):
+                dict.__init__(self)
+                self.__dict__ = self
+        x = X()
+        x.attr = 42
+        wr = weakref.ref(x)
+        del x
+        test_support.gc_collect()
+        self.assertIsNone(wr())
+        for o in gc.get_objects():
+            self.assertIsNot(type(o), X)
+
 class DictProxyTests(unittest.TestCase):
     def setUp(self):
         class C(object):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -9,6 +9,9 @@
 Core and Builtins
 -----------------
 
+- Issue #1469629: Allow cycles through an object's __dict__ slot to be
+  collected. (For example if ``x.__dict__ is x``).
+
 - Issue #13521: dict.setdefault() now does only one lookup for the given key,
   making it "atomic" for many purposes.  Patch by Filip Gruszczyński.
 
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -876,8 +876,13 @@
         assert(base);
     }
 
-    /* There's no need to clear the instance dict (if any);
-       the collector will call its tp_clear handler. */
+    /* Clear the instance dict (if any), to break cycles involving only
+       __dict__ slots (as in the case 'self.__dict__ is self'). */
+    if (type->tp_dictoffset != base->tp_dictoffset) {
+        PyObject **dictptr = _PyObject_GetDictPtr(self);
+        if (dictptr && *dictptr)
+            Py_CLEAR(*dictptr);
+    }
 
     if (baseclear)
         return baseclear(self);

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


More information about the Python-checkins mailing list