]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-104619: never leak comprehension locals to outer locals() (#104637)
authorCarl Meyer <carl@oddbird.net>
Fri, 19 May 2023 01:50:24 +0000 (19:50 -0600)
committerGitHub <noreply@github.com>
Fri, 19 May 2023 01:50:24 +0000 (18:50 -0700)
Lib/test/test_listcomps.py
Python/compile.c

index fdd2d66b49e06b6139ccb13e95ab69267729c36f..185658ab5a4ca8a1a39278a8aa588befc7d354d2 100644 (file)
@@ -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}
 
index 2db03f7176ea0225d959a67fd4e5aa4010efcbc0..cfe8224a7e27c63eabb282921c87d481f9342b26 100644 (file)
@@ -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) {