Commit a93342b8 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #21897: Fix a crash with the f_locals attribute with closure variables...

Issue #21897: Fix a crash with the f_locals attribute with closure variables when frame.clear() has been called.
parents 92e8deeb acc8cf2c
import gc import gc
import sys import sys
import types
import unittest import unittest
import weakref import weakref
...@@ -109,6 +110,57 @@ class ClearTest(unittest.TestCase): ...@@ -109,6 +110,57 @@ class ClearTest(unittest.TestCase):
self.assertIs(None, wr()) 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(): def test_main():
support.run_unittest(__name__) support.run_unittest(__name__)
......
...@@ -10,6 +10,9 @@ Release date: TBA ...@@ -10,6 +10,9 @@ Release date: TBA
Core and Builtins 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 - Issue #21205: Add a new ``__qualname__`` attribute to generator, the
qualified name, and use it in the representation of a generator qualified name, and use it in the representation of a generator
(``repr(gen)``). The default name of the generator (``__name__`` attribute) (``repr(gen)``). The default name of the generator (``__name__`` attribute)
......
...@@ -786,7 +786,7 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, ...@@ -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 *key = PyTuple_GET_ITEM(map, j);
PyObject *value = values[j]; PyObject *value = values[j];
assert(PyUnicode_Check(key)); assert(PyUnicode_Check(key));
if (deref) { if (deref && value != NULL) {
assert(PyCell_Check(value)); assert(PyCell_Check(value));
value = PyCell_GET(value); value = PyCell_GET(value);
} }
......
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