[Python-checkins] gh-104619: never leak comprehension locals to outer locals() (#104637)
JelleZijlstra
webhook-mailer at python.org
Thu May 18 21:50:31 EDT 2023
https://github.com/python/cpython/commit/70c77964778817907fbcc2a047a2abad4eb6e127
commit: 70c77964778817907fbcc2a047a2abad4eb6e127
branch: main
author: Carl Meyer <carl at oddbird.net>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2023-05-18T18:50:24-07:00
summary:
gh-104619: never leak comprehension locals to outer locals() (#104637)
files:
M Lib/test/test_listcomps.py
M Python/compile.c
diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py
index fdd2d66b49e0..185658ab5a4c 100644
--- a/Lib/test/test_listcomps.py
+++ b/Lib/test/test_listcomps.py
@@ -516,6 +516,19 @@ def test_assign_to_comp_iter_var_in_outer_function(self):
"""
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 2db03f7176ea..cfe8224a7e27 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) {
More information about the Python-checkins
mailing list