[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 <gaogaotiantian@hotmail.com>

* Update test

* PR feedback

* formatting

* comment

---------

Co-authored-by: Tian Gao <gaogaotiantian@hotmail.com>
This commit is contained in:
Kyle Cutler 2025-03-10 17:27:07 -07:00 committed by GitHub
parent fcf1f57d91
commit 33605da91c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 0 deletions

View file

@ -709,6 +709,23 @@ def test_multiple_comprehension_name_reuse(self):
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

View file

@ -0,0 +1,2 @@
Fixed an issue where ``_PyFrame_LocalsToFast`` tries to write module level
values to hidden fasts.

View file

@ -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. */