Skip to content

Commit 563c7dc

Browse files
authored
gh-104404: fix crasher with nested comprehensions plus lambdas (#104442)
1 parent 1eb950c commit 563c7dc

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

Lib/test/test_listcomps.py

+8
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,14 @@ def test_nested_3(self):
338338
outputs = {"y": [1, 3, 5]}
339339
self._check_in_scopes(code, outputs)
340340

341+
def test_nested_4(self):
342+
code = """
343+
items = [([lambda: x for x in range(2)], lambda: x) for x in range(3)]
344+
out = [([fn() for fn in fns], fn()) for fns, fn in items]
345+
"""
346+
outputs = {"out": [([1, 1], 2), ([1, 1], 2), ([1, 1], 2)]}
347+
self._check_in_scopes(code, outputs)
348+
341349
def test_nameerror(self):
342350
code = """
343351
[x for x in [1]]

Python/symtable.c

+14-7
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,8 @@ is_free_in_any_child(PySTEntryObject *entry, PyObject *key)
575575

576576
static int
577577
inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
578-
PyObject *scopes, PyObject *comp_free)
578+
PyObject *scopes, PyObject *comp_free,
579+
PyObject *promote_to_cell)
579580
{
580581
PyObject *k, *v;
581582
Py_ssize_t pos = 0;
@@ -611,7 +612,9 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
611612
// cell vars in comprehension that are locals in outer scope
612613
// must be promoted to cell so u_cellvars isn't wrong
613614
if (scope == CELL && ste->ste_type == FunctionBlock) {
614-
SET_SCOPE(scopes, k, scope);
615+
if (PySet_Add(promote_to_cell, k) < 0) {
616+
return 0;
617+
}
615618
}
616619

617620
// free vars in comprehension that are locals in outer scope can
@@ -638,7 +641,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
638641
*/
639642

640643
static int
641-
analyze_cells(PyObject *scopes, PyObject *free)
644+
analyze_cells(PyObject *scopes, PyObject *free, PyObject *promote_to_cell)
642645
{
643646
PyObject *name, *v, *v_cell;
644647
int success = 0;
@@ -653,7 +656,7 @@ analyze_cells(PyObject *scopes, PyObject *free)
653656
scope = PyLong_AS_LONG(v);
654657
if (scope != LOCAL)
655658
continue;
656-
if (!PySet_Contains(free, name))
659+
if (!PySet_Contains(free, name) && !PySet_Contains(promote_to_cell, name))
657660
continue;
658661
/* Replace LOCAL with CELL for this name, and remove
659662
from free. It is safe to replace the value of name
@@ -803,7 +806,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
803806
PyObject *global)
804807
{
805808
PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL;
806-
PyObject *newglobal = NULL, *newfree = NULL;
809+
PyObject *newglobal = NULL, *newfree = NULL, *promote_to_cell = NULL;
807810
PyObject *temp;
808811
int success = 0;
809812
Py_ssize_t i, pos = 0;
@@ -835,6 +838,9 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
835838
newbound = PySet_New(NULL);
836839
if (!newbound)
837840
goto error;
841+
promote_to_cell = PySet_New(NULL);
842+
if (!promote_to_cell)
843+
goto error;
838844

839845
/* Class namespace has no effect on names visible in
840846
nested functions, so populate the global and bound
@@ -915,7 +921,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
915921
goto error;
916922
}
917923
if (inline_comp) {
918-
if (!inline_comprehension(ste, entry, scopes, child_free)) {
924+
if (!inline_comprehension(ste, entry, scopes, child_free, promote_to_cell)) {
919925
Py_DECREF(child_free);
920926
goto error;
921927
}
@@ -946,7 +952,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
946952
}
947953

948954
/* Check if any local variables must be converted to cell variables */
949-
if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree))
955+
if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree, promote_to_cell))
950956
goto error;
951957
else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree))
952958
goto error;
@@ -966,6 +972,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
966972
Py_XDECREF(newbound);
967973
Py_XDECREF(newglobal);
968974
Py_XDECREF(newfree);
975+
Py_XDECREF(promote_to_cell);
969976
if (!success)
970977
assert(PyErr_Occurred());
971978
return success;

0 commit comments

Comments
 (0)