# UNDF: UNDF-2026-000000039 # cpython-0001: codegen pattern-match stores duplicate check O(S^2) # # In Python/codegen.c, codegen_pattern_helper_store_name() and the # mapping-pattern loop both call PySequence_Contains(pc->stores, name) # where pc->stores is a PyList. Each call is O(S) where S is the number # of store names accumulated so far. Since this is called once per store # name, the total cost is O(S^2). # # Fix: Use a PySet alongside pc->stores for O(1) membership checks. # pc->stores remains a list (order matters for stack rotation), but # a parallel set provides O(1) duplicate detection. # # Severity: MEDIUM — match statements with many capture variables # (e.g., structural pattern matching on large data classes) hit O(S^2). # At S=100 capture variables, ~5000 comparisons vs 100 set lookups. # --- a/Python/codegen.c +++ b/Python/codegen.c @@ -5908,7 +5908,7 @@ codegen_pattern_helper_store_name(compiler *c, location loc, ADDOP(c, loc, POP_TOP); return SUCCESS; } - int duplicate = PySequence_Contains(pc->stores, n); + int duplicate = PySet_Contains(pc->stores_set, n); RETURN_IF_ERROR(duplicate); if (duplicate) { return codegen_error_duplicate_store(c, loc, n); @@ -5916,6 +5916,7 @@ codegen_pattern_helper_store_name(compiler *c, location loc, Py_ssize_t rotations = pc->on_top + PyList_GET_SIZE(pc->stores) + 1; RETURN_IF_ERROR(codegen_pattern_helper_rotate(c, loc, rotations)); RETURN_IF_ERROR(PyList_Append(pc->stores, n)); + RETURN_IF_ERROR(PySet_Add(pc->stores_set, n)); return SUCCESS; } @@ -6395,7 +6396,7 @@ codegen_pattern_helper_store_name(compiler *c, location loc, // Update the list of previous stores with this new name, checking for // duplicates: PyObject *name = PyList_GET_ITEM(control, i); - int dupe = PySequence_Contains(pc->stores, name); + int dupe = PySet_Contains(pc->stores_set, name); if (dupe < 0) { goto error; } @@ -6405,6 +6406,9 @@ codegen_pattern_helper_store_name(compiler *c, location loc, } if (PyList_Append(pc->stores, name)) { goto error; + } + if (PySet_Add(pc->stores_set, name)) { + goto error; } }