From acc8cf2cfa18c445e8c9b324206eb7c5e392bcb7 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Fri, 4 Jul 2014 20:24:13 -0400 Subject: [PATCH] Issue #21897: Fix a crash with the f_locals attribute with closure variables when frame.clear() has been called. --- Lib/test/test_frame.py | 52 ++++++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ Objects/frameobject.c | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 2dd5780c889..c402ec394e1 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -1,5 +1,6 @@ import gc import sys +import types import unittest import weakref @@ -109,6 +110,57 @@ class ClearTest(unittest.TestCase): self.assertIs(None, wr()) +class FrameLocalsTest(unittest.TestCase): + """ + Tests for the .f_locals attribute. + """ + + def make_frames(self): + def outer(): + x = 5 + y = 6 + def inner(): + z = x + 2 + 1/0 + t = 9 + return inner() + try: + outer() + except ZeroDivisionError as e: + tb = e.__traceback__ + frames = [] + while tb: + frames.append(tb.tb_frame) + tb = tb.tb_next + return frames + + def test_locals(self): + f, outer, inner = self.make_frames() + outer_locals = outer.f_locals + self.assertIsInstance(outer_locals.pop('inner'), types.FunctionType) + self.assertEqual(outer_locals, {'x': 5, 'y': 6}) + inner_locals = inner.f_locals + self.assertEqual(inner_locals, {'x': 5, 'z': 7}) + + def test_clear_locals(self): + # Test f_locals after clear() (issue #21897) + f, outer, inner = self.make_frames() + outer.clear() + inner.clear() + self.assertEqual(outer.f_locals, {}) + self.assertEqual(inner.f_locals, {}) + + 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, {}) + + def test_main(): support.run_unittest(__name__) diff --git a/Misc/NEWS b/Misc/NEWS index a413f48630a..4e083233a54 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Core and Builtins Library ------- +- Issue #21897: Fix a crash with the f_locals attribute with closure + variables when frame.clear() has been called. + - Issue #21151: Fixed a segfault in the winreg module when ``None`` is passed as a ``REG_BINARY`` value to SetValueEx. Patch by John Ehresman. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 0d6229360e6..55ee5630f67 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -786,7 +786,7 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, PyObject *key = PyTuple_GET_ITEM(map, j); PyObject *value = values[j]; assert(PyUnicode_Check(key)); - if (deref) { + if (deref && value != NULL) { assert(PyCell_Check(value)); value = PyCell_GET(value); }