diff options
author | Guido van Rossum <guido@python.org> | 2013-05-10 15:47:42 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2013-05-10 15:47:42 (GMT) |
commit | 6832c81d5d2d730c38bab001e0c1b4b0569dd5ef (patch) | |
tree | f4725451768bda1987adf4eca22d2e232018fd9f /Lib | |
parent | 8c01ffa6ede5da92ab144ad2ea609a96e308b1e6 (diff) | |
download | cpython-6832c81d5d2d730c38bab001e0c1b4b0569dd5ef.zip cpython-6832c81d5d2d730c38bab001e0c1b4b0569dd5ef.tar.gz cpython-6832c81d5d2d730c38bab001e0c1b4b0569dd5ef.tar.bz2 |
#17927: Keep frame from referencing cell-ified arguments.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_scope.py | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py index f4ed244..1c06224 100644 --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,3 +1,4 @@ +import gc import unittest from test.support import check_syntax_error, cpython_only, run_unittest @@ -713,7 +714,6 @@ class ScopeTests(unittest.TestCase): def b(): global a - def testClassNamespaceOverridesClosure(self): # See #17853. x = 42 @@ -727,6 +727,45 @@ class ScopeTests(unittest.TestCase): self.assertFalse(hasattr(X, "x")) self.assertEqual(x, 42) + @cpython_only + def testCellLeak(self): + # Issue 17927. + # + # The issue was that if self was part of a cycle involving the + # frame of a method call, *and* the method contained a nested + # function referencing self, thereby forcing 'self' into a + # cell, setting self to None would not be enough to break the + # frame -- the frame had another reference to the instance, + # which could not be cleared by the code running in the frame + # (though it will be cleared when the frame is collected). + # Without the lambda, setting self to None is enough to break + # the cycle. + logs = [] + class Canary: + def __del__(self): + logs.append('canary') + class Base: + def dig(self): + pass + class Tester(Base): + def __init__(self): + self.canary = Canary() + def dig(self): + if 0: + lambda: self + try: + 1/0 + except Exception as exc: + self.exc = exc + super().dig() + self = None # Break the cycle + tester = Tester() + tester.dig() + del tester + logs.append('collect') + gc.collect() + self.assertEqual(logs, ['canary', 'collect']) + def test_main(): run_unittest(ScopeTests) |