Skip to content

Commit 70c7796

Browse files
authoredMay 19, 2023
gh-104619: never leak comprehension locals to outer locals() (#104637)
1 parent 86e6f16 commit 70c7796

File tree

2 files changed

+32
-21
lines changed

2 files changed

+32
-21
lines changed
 

‎Lib/test/test_listcomps.py

+13
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,19 @@ def test_assign_to_comp_iter_var_in_outer_function(self):
516516
"""
517517
self._check_in_scopes(code, {"a": [1]}, scopes=["function"])
518518

519+
def test_no_leakage_to_locals(self):
520+
code = """
521+
def b():
522+
[a for b in [1] for _ in []]
523+
return b, locals()
524+
r, s = b()
525+
x = r is b
526+
y = list(s.keys())
527+
"""
528+
self._check_in_scopes(code, {"x": True, "y": []}, scopes=["module"])
529+
self._check_in_scopes(code, {"x": True, "y": ["b"]}, scopes=["function"])
530+
self._check_in_scopes(code, raises=NameError, scopes=["class"])
531+
519532

520533
__test__ = {'doctests' : doctests}
521534

‎Python/compile.c

+19-21
Original file line numberDiff line numberDiff line change
@@ -5490,31 +5490,29 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
54905490
}
54915491
Py_DECREF(outv);
54925492
}
5493-
if (outsc == LOCAL || outsc == CELL || outsc == FREE) {
5494-
// local names bound in comprehension must be isolated from
5495-
// outer scope; push existing value (which may be NULL if
5496-
// not defined) on stack
5493+
// local names bound in comprehension must be isolated from
5494+
// outer scope; push existing value (which may be NULL if
5495+
// not defined) on stack
5496+
if (state->pushed_locals == NULL) {
5497+
state->pushed_locals = PyList_New(0);
54975498
if (state->pushed_locals == NULL) {
5498-
state->pushed_locals = PyList_New(0);
5499-
if (state->pushed_locals == NULL) {
5500-
return ERROR;
5501-
}
5502-
}
5503-
// in the case of a cell, this will actually push the cell
5504-
// itself to the stack, then we'll create a new one for the
5505-
// comprehension and restore the original one after
5506-
ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames);
5507-
if (scope == CELL) {
5508-
if (outsc == FREE) {
5509-
ADDOP_NAME(c, loc, MAKE_CELL, k, freevars);
5510-
} else {
5511-
ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars);
5512-
}
5513-
}
5514-
if (PyList_Append(state->pushed_locals, k) < 0) {
55155499
return ERROR;
55165500
}
55175501
}
5502+
// in the case of a cell, this will actually push the cell
5503+
// itself to the stack, then we'll create a new one for the
5504+
// comprehension and restore the original one after
5505+
ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames);
5506+
if (scope == CELL) {
5507+
if (outsc == FREE) {
5508+
ADDOP_NAME(c, loc, MAKE_CELL, k, freevars);
5509+
} else {
5510+
ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars);
5511+
}
5512+
}
5513+
if (PyList_Append(state->pushed_locals, k) < 0) {
5514+
return ERROR;
5515+
}
55185516
}
55195517
}
55205518
if (state->pushed_locals) {

0 commit comments

Comments
 (0)
Please sign in to comment.