Author: Armin Rigo <[email protected]>
Branch: extradoc
Changeset: r5750:b6cd4ef2e6cc
Date: 2016-11-20 17:16 +0100
http://bitbucket.org/pypy/extradoc/changeset/b6cd4ef2e6cc/

Log:    Another CPython 3.5 failure

diff --git a/planning/py3.5/cpython-crashers.rst 
b/planning/py3.5/cpython-crashers.rst
--- a/planning/py3.5/cpython-crashers.rst
+++ b/planning/py3.5/cpython-crashers.rst
@@ -144,3 +144,38 @@
     except IndexError:
         assert next(gen) is 1
     assert next(gen) is 2    # <==
+
+* frame.clear() does not clear f_locals, unlike what a test says
+  (Lib/test/test_frame.py)::
+
+    def test_locals_clear_locals(self):
+        # Test f_locals before and after clear() (to exercise caching)
+        f, outer, inner = self.make_frames()
+        outer.f_locals
+        inner.f_locals
+        outer.clear()
+        inner.clear()
+        self.assertEqual(outer.f_locals, {})
+        self.assertEqual(inner.f_locals, {})
+
+  This test passes, but the C-level PyFrameObject has got a strong
+  reference to f_locals, which is only updated (to be empty) if the
+  Python code tries to read this attribute.  In the normal case,
+  code that calls clear() but doesn't read f_locals afterwards will
+  still leak everything contained in the C-level f_locals field.  This
+  can be shown by this failing test::
+
+    import sys
+
+    def g():
+        x = 42
+        return sys._getframe()
+
+    frame = g()
+    d = frame.f_locals
+    frame.clear()
+    print(d)
+    assert d == {}   # fails!  but 'assert d is frame.f_locals' passes,
+                     # which shows that this dict is kept alive by
+                     # 'frame'; and we've seen that it is non-empty
+                     # as long as we don't read frame.f_locals.
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to