Commit acc8cf2c 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.
parent e8651286
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__)
......
...@@ -27,6 +27,9 @@ Core and Builtins ...@@ -27,6 +27,9 @@ Core and Builtins
Library 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 - Issue #21151: Fixed a segfault in the winreg module when ``None`` is passed
as a ``REG_BINARY`` value to SetValueEx. Patch by John Ehresman. as a ``REG_BINARY`` value to SetValueEx. Patch by John Ehresman.
......
...@@ -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