diff options
author | Carl Meyer <carl@oddbird.net> | 2023-05-13 00:42:04 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-13 00:42:04 (GMT) |
commit | 563c7dcba0ea1070698b77129628e9e1c86d34e2 (patch) | |
tree | 9be92e0a05a43a77769dc68f841bd61bdfb5b1cf /Python/symtable.c | |
parent | 1eb950ca55b3e0b6524b3f03b0b519723916eca2 (diff) | |
download | cpython-563c7dcba0ea1070698b77129628e9e1c86d34e2.zip cpython-563c7dcba0ea1070698b77129628e9e1c86d34e2.tar.gz cpython-563c7dcba0ea1070698b77129628e9e1c86d34e2.tar.bz2 |
gh-104404: fix crasher with nested comprehensions plus lambdas (#104442)
Diffstat (limited to 'Python/symtable.c')
-rw-r--r-- | Python/symtable.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/Python/symtable.c b/Python/symtable.c index 9361674..2c29f60 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -575,7 +575,8 @@ is_free_in_any_child(PySTEntryObject *entry, PyObject *key) static int inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, - PyObject *scopes, PyObject *comp_free) + PyObject *scopes, PyObject *comp_free, + PyObject *promote_to_cell) { PyObject *k, *v; Py_ssize_t pos = 0; @@ -611,7 +612,9 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, // cell vars in comprehension that are locals in outer scope // must be promoted to cell so u_cellvars isn't wrong if (scope == CELL && ste->ste_type == FunctionBlock) { - SET_SCOPE(scopes, k, scope); + if (PySet_Add(promote_to_cell, k) < 0) { + return 0; + } } // free vars in comprehension that are locals in outer scope can @@ -638,7 +641,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, */ static int -analyze_cells(PyObject *scopes, PyObject *free) +analyze_cells(PyObject *scopes, PyObject *free, PyObject *promote_to_cell) { PyObject *name, *v, *v_cell; int success = 0; @@ -653,7 +656,7 @@ analyze_cells(PyObject *scopes, PyObject *free) scope = PyLong_AS_LONG(v); if (scope != LOCAL) continue; - if (!PySet_Contains(free, name)) + if (!PySet_Contains(free, name) && !PySet_Contains(promote_to_cell, name)) continue; /* Replace LOCAL with CELL for this name, and remove from free. It is safe to replace the value of name @@ -803,7 +806,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, PyObject *global) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; - PyObject *newglobal = NULL, *newfree = NULL; + PyObject *newglobal = NULL, *newfree = NULL, *promote_to_cell = NULL; PyObject *temp; int success = 0; Py_ssize_t i, pos = 0; @@ -835,6 +838,9 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, newbound = PySet_New(NULL); if (!newbound) goto error; + promote_to_cell = PySet_New(NULL); + if (!promote_to_cell) + goto error; /* Class namespace has no effect on names visible in nested functions, so populate the global and bound @@ -915,7 +921,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, goto error; } if (inline_comp) { - if (!inline_comprehension(ste, entry, scopes, child_free)) { + if (!inline_comprehension(ste, entry, scopes, child_free, promote_to_cell)) { Py_DECREF(child_free); goto error; } @@ -946,7 +952,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, } /* Check if any local variables must be converted to cell variables */ - if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree)) + if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree, promote_to_cell)) goto error; else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree)) goto error; @@ -966,6 +972,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, Py_XDECREF(newbound); Py_XDECREF(newglobal); Py_XDECREF(newfree); + Py_XDECREF(promote_to_cell); if (!success) assert(PyErr_Occurred()); return success; |