52 lines
2.7 KiB
Diff
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;
|
|
}
|