summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2023-05-19 01:50:24 (GMT)
committerGitHub <noreply@github.com>2023-05-19 01:50:24 (GMT)
commit70c77964778817907fbcc2a047a2abad4eb6e127 (patch)
tree25d5c17e0acc78dbd0783f344abb63436d38e32c
parent86e6f16ccb97f66f2b9a31191ce347dca499d48c (diff)
downloadcpython-70c77964778817907fbcc2a047a2abad4eb6e127.zip
cpython-70c77964778817907fbcc2a047a2abad4eb6e127.tar.gz
cpython-70c77964778817907fbcc2a047a2abad4eb6e127.tar.bz2
gh-104619: never leak comprehension locals to outer locals() (#104637)
-rw-r--r--Lib/test/test_listcomps.py13
-rw-r--r--Python/compile.c40
2 files changed, 32 insertions, 21 deletions
diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py
index fdd2d66..185658a 100644
--- a/Lib/test/test_listcomps.py
+++ b/Lib/test/test_listcomps.py
@@ -516,6 +516,19 @@ class ListComprehensionTest(unittest.TestCase):
"""
self._check_in_scopes(code, {"a": [1]}, scopes=["function"])
+ def test_no_leakage_to_locals(self):
+ code = """
+ def b():
+ [a for b in [1] for _ in []]
+ return b, locals()
+ r, s = b()
+ x = r is b
+ y = list(s.keys())
+ """
+ self._check_in_scopes(code, {"x": True, "y": []}, scopes=["module"])
+ self._check_in_scopes(code, {"x": True, "y": ["b"]}, scopes=["function"])
+ self._check_in_scopes(code, raises=NameError, scopes=["class"])
+
__test__ = {'doctests' : doctests}
diff --git a/Python/compile.c b/Python/compile.c
index 2db03f7..cfe8224 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -5490,31 +5490,29 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
}
Py_DECREF(outv);
}
- if (outsc == LOCAL || outsc == CELL || outsc == FREE) {
- // local names bound in comprehension must be isolated from
- // outer scope; push existing value (which may be NULL if
- // not defined) on stack
+ // local names bound in comprehension must be isolated from
+ // outer scope; push existing value (which may be NULL if
+ // not defined) on stack
+ if (state->pushed_locals == NULL) {
+ state->pushed_locals = PyList_New(0);
if (state->pushed_locals == NULL) {
- state->pushed_locals = PyList_New(0);
- if (state->pushed_locals == NULL) {
- return ERROR;
- }
- }
- // in the case of a cell, this will actually push the cell
- // itself to the stack, then we'll create a new one for the
- // comprehension and restore the original one after
- ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames);
- if (scope == CELL) {
- if (outsc == FREE) {
- ADDOP_NAME(c, loc, MAKE_CELL, k, freevars);
- } else {
- ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars);
- }
- }
- if (PyList_Append(state->pushed_locals, k) < 0) {
return ERROR;
}
}
+ // in the case of a cell, this will actually push the cell
+ // itself to the stack, then we'll create a new one for the
+ // comprehension and restore the original one after
+ ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames);
+ if (scope == CELL) {
+ if (outsc == FREE) {
+ ADDOP_NAME(c, loc, MAKE_CELL, k, freevars);
+ } else {
+ ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars);
+ }
+ }
+ if (PyList_Append(state->pushed_locals, k) < 0) {
+ return ERROR;
+ }
}
}
if (state->pushed_locals) {