From 33605da91cfcdb88673892fef1fe2eb6fea2cde2 Mon Sep 17 00:00:00 2001 From: Kyle Cutler <67761731+kycutler@users.noreply.github.com> Date: Mon, 10 Mar 2025 17:27:07 -0700 Subject: [PATCH] [3.12] gh-130809: Fix `PyFrame_LocalsToFast` copying the wrong value (#130816) * gh-130809: Fix `PyFrame_LocalsToFast` copying the wrong value * Skip hidden locals * test, blurb * Update Misc/NEWS.d/next/Core_and_Builtins/2025-03-04-12-52-21.gh-issue-130809.fSXq60.rst Co-authored-by: Tian Gao * Update test * PR feedback * formatting * comment --------- Co-authored-by: Tian Gao --- Lib/test/test_listcomps.py | 17 +++++++++++++++++ ...25-03-04-12-52-21.gh-issue-130809.fSXq60.rst | 2 ++ Objects/frameobject.c | 3 +++ 3 files changed, 22 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-03-04-12-52-21.gh-issue-130809.fSXq60.rst diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 2065afd455de..3e2ef1809779 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -709,6 +709,23 @@ class ListComprehensionTest(unittest.TestCase): self._check_in_scopes(code, {"x": 2, "y": [3]}, ns={"x": 3}, scopes=["class"]) self._check_in_scopes(code, {"x": 2, "y": [2]}, ns={"x": 3}, scopes=["function", "module"]) + def test_name_collision_locals(self): + # GH-130809: The existence of a hidden fast from list comprehension + # should not cause frame.f_locals on module level to return a new dict + # every time it is accessed. + + code = """ + import sys + frame = sys._getframe() + f_locals = frame.f_locals + foo = 1 + [foo for foo in [0]] + # calls _PyFrame_LocalsToFast which triggers the issue + from abc import * + same_f_locals = frame.f_locals is f_locals + """ + self._check_in_scopes(code, {"foo": 1, "same_f_locals": True}, scopes=["module"]) + def test_exception_locations(self): # The location of an exception raised from __init__ or # __next__ should should be the iterator expression diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-03-04-12-52-21.gh-issue-130809.fSXq60.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-03-04-12-52-21.gh-issue-130809.fSXq60.rst new file mode 100644 index 000000000000..419b2a3eb850 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-03-04-12-52-21.gh-issue-130809.fSXq60.rst @@ -0,0 +1,2 @@ +Fixed an issue where ``_PyFrame_LocalsToFast`` tries to write module level +values to hidden fasts. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d33c3cde526e..44f2726f2cca 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1405,6 +1405,9 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) if (kind & CO_FAST_FREE && !(co->co_flags & CO_OPTIMIZED)) { continue; } + if (kind & CO_FAST_HIDDEN) { + continue; + } PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); PyObject *value = PyObject_GetItem(locals, name); /* We only care about NULLs if clear is true. */ -- 2.47.3