Commit 60ea34b1 authored by Benjamin Peterson's avatar Benjamin Peterson

allow cycles throught the __dict__ slot to be cleared (closes #1469629)

Patch from Armin, test from me.
parent 353fad99
import __builtin__ import __builtin__
import gc
import sys import sys
import types import types
import unittest import unittest
import weakref
from copy import deepcopy from copy import deepcopy
from test import test_support from test import test_support
...@@ -1127,7 +1129,6 @@ order (MRO) for bases """ ...@@ -1127,7 +1129,6 @@ order (MRO) for bases """
self.assertEqual(Counted.counter, 0) self.assertEqual(Counted.counter, 0)
# Test lookup leaks [SF bug 572567] # Test lookup leaks [SF bug 572567]
import gc
if hasattr(gc, 'get_objects'): if hasattr(gc, 'get_objects'):
class G(object): class G(object):
def __cmp__(self, other): def __cmp__(self, other):
...@@ -4541,7 +4542,6 @@ order (MRO) for bases """ ...@@ -4541,7 +4542,6 @@ order (MRO) for bases """
self.assertRaises(AttributeError, getattr, C(), "attr") self.assertRaises(AttributeError, getattr, C(), "attr")
self.assertEqual(descr.counter, 4) self.assertEqual(descr.counter, 4)
import gc
class EvilGetattribute(object): class EvilGetattribute(object):
# This used to segfault # This used to segfault
def __getattr__(self, name): def __getattr__(self, name):
...@@ -4590,6 +4590,21 @@ order (MRO) for bases """ ...@@ -4590,6 +4590,21 @@ order (MRO) for bases """
foo = Foo() foo = Foo()
str(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): class DictProxyTests(unittest.TestCase):
def setUp(self): def setUp(self):
class C(object): class C(object):
......
...@@ -9,6 +9,9 @@ What's New in Python 2.7.3 release candidate 1? ...@@ -9,6 +9,9 @@ What's New in Python 2.7.3 release candidate 1?
Core and Builtins 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, - Issue #13521: dict.setdefault() now does only one lookup for the given key,
making it "atomic" for many purposes. Patch by Filip Gruszczyński. making it "atomic" for many purposes. Patch by Filip Gruszczyński.
......
...@@ -876,8 +876,13 @@ subtype_clear(PyObject *self) ...@@ -876,8 +876,13 @@ subtype_clear(PyObject *self)
assert(base); assert(base);
} }
/* There's no need to clear the instance dict (if any); /* Clear the instance dict (if any), to break cycles involving only
the collector will call its tp_clear handler. */ __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) if (baseclear)
return baseclear(self); return baseclear(self);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment