Skip to content

Commit 33605da

Browse files
[3.12] pythongh-130809: Fix PyFrame_LocalsToFast copying the wrong value (python#130816)
* pythongh-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>
1 parent fcf1f57 commit 33605da

File tree

3 files changed

+22
-0
lines changed

3 files changed

+22
-0
lines changed

Lib/test/test_listcomps.py

+17
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,23 @@ def test_multiple_comprehension_name_reuse(self):
709709
self._check_in_scopes(code, {"x": 2, "y": [3]}, ns={"x": 3}, scopes=["class"])
710710
self._check_in_scopes(code, {"x": 2, "y": [2]}, ns={"x": 3}, scopes=["function", "module"])
711711

712+
def test_name_collision_locals(self):
713+
# GH-130809: The existence of a hidden fast from list comprehension
714+
# should not cause frame.f_locals on module level to return a new dict
715+
# every time it is accessed.
716+
717+
code = """
718+
import sys
719+
frame = sys._getframe()
720+
f_locals = frame.f_locals
721+
foo = 1
722+
[foo for foo in [0]]
723+
# calls _PyFrame_LocalsToFast which triggers the issue
724+
from abc import *
725+
same_f_locals = frame.f_locals is f_locals
726+
"""
727+
self._check_in_scopes(code, {"foo": 1, "same_f_locals": True}, scopes=["module"])
728+
712729
def test_exception_locations(self):
713730
# The location of an exception raised from __init__ or
714731
# __next__ should should be the iterator expression
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed an issue where ``_PyFrame_LocalsToFast`` tries to write module level
2+
values to hidden fasts.

Objects/frameobject.c

+3
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,9 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
14051405
if (kind & CO_FAST_FREE && !(co->co_flags & CO_OPTIMIZED)) {
14061406
continue;
14071407
}
1408+
if (kind & CO_FAST_HIDDEN) {
1409+
continue;
1410+
}
14081411
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
14091412
PyObject *value = PyObject_GetItem(locals, name);
14101413
/* We only care about NULLs if clear is true. */

0 commit comments

Comments
 (0)