java-topology/defects/inkscape/patch/inkscape-0003-selection-chemistry-get-all-items-exclude-vector.patch

52 lines
2.7 KiB
Diff

# UNDF: UNDF-2026-000000785
# UNDF: (leave blank)
# CWE-407: selection-chemistry.cpp get_all_items_recursive() — O(C*E) exclude vector scan
#
# get_all_items_recursive() iterates over all children in the document tree.
# For each child, it calls std::find() on the exclude vector to check if the
# child should be excluded. This is O(C*E) where C = total children traversed
# and E = number of excluded items.
#
# Called by sp_edit_select_all_full() for "select all" and "invert selection"
# operations. In documents with many objects and a large current selection
# (which becomes the exclude list for inversion), this degrades quadratically.
#
# Fix: convert exclude vector to std::unordered_set for O(1) lookup.
#
# Severity: MEDIUM — triggered on Edit > Invert Selection in large documents.
# Overhead: ~200x at C=1000 children, E=500 excluded.
#
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -648,7 +648,7 @@
-static void get_all_items_recursive(std::vector<SPItem*> &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::vector<SPItem*> const &exclude)
+static void get_all_items_recursive(std::vector<SPItem*> &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::unordered_set<SPItem*> const &exclude_set)
{
for (auto &child : from->children) {
auto item = cast<SPItem>(&child);
@@ -656,7 +656,7 @@
!desktop->layerManager().isLayer(item) &&
(!onlysensitive || !item->isLocked()) &&
(!onlyvisible || !desktop->itemIsHidden(item)) &&
- (exclude.empty() || std::find(exclude.begin(), exclude.end(), &child) == exclude.end()))
+ (exclude_set.empty() || exclude_set.find(item) == exclude_set.end()))
{
list.emplace_back(item);
}
@@ -664,14 +664,15 @@
if (ingroups || (item && desktop->layerManager().isLayer(item))) {
- get_all_items_recursive(list, &child, desktop, onlyvisible, onlysensitive, ingroups, exclude);
+ get_all_items_recursive(list, &child, desktop, onlyvisible, onlysensitive, ingroups, exclude_set);
}
}
}
std::vector<SPItem*> get_all_items(SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::vector<SPItem*> const &exclude)
{
+ std::unordered_set<SPItem*> exclude_set(exclude.begin(), exclude.end());
std::vector<SPItem*> list;
- get_all_items_recursive(list, from, desktop, onlyvisible, onlysensitive, ingroups, exclude);
+ get_all_items_recursive(list, from, desktop, onlyvisible, onlysensitive, ingroups, exclude_set);
std::reverse(list.begin(), list.end());
return list;
}