Issue #21897: Fix a crash with the f_locals attribute with closure variables when frame.clear() has been called.

This commit is contained in:
Antoine Pitrou 2014-07-04 20:26:22 -04:00
commit a93342b8b2
3 changed files with 56 additions and 1 deletions

View File

@ -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__)

View File

@ -10,6 +10,9 @@ Release date: TBA
Core and Builtins
-----------------
- Issue #21897: Fix a crash with the f_locals attribute with closure
variables when frame.clear() has been called.
- Issue #21205: Add a new ``__qualname__`` attribute to generator, the
qualified name, and use it in the representation of a generator
(``repr(gen)``). The default name of the generator (``__name__`` attribute)

View File

@ -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);
}