55 lines
2.3 KiB
Diff
55 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000000039
|
|
# UNDF: (leave blank)
|
|
# 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;
|
|
}
|
|
}
|