java-topology/defects/scribus/patch/scribus-0003-selection-addItems-contains.patch
russell@unturf.com 13db08af50 darktable+scribus: CWE-407 scan — 6 defects (3 darktable, 3 scribus)
darktable-0001: map_locations image diff g_list_find O(N*M) MEDIUM 375x
darktable-0002: tags _tag_add_tags_to_list g_list_find O(T*L) MEDIUM 375x
darktable-0003: map view clustering g_list_find(sel_imgs) O(I²×S) HIGH 160x
scribus-0001: getSortedStyleList retList.contains O(N²) MEDIUM 167x (×4 copies)
scribus-0002: getUsedPatterns results.contains O(I×R) MEDIUM 98x
scribus-0003: Selection::addItems m_SelList.contains O(N×M) MEDIUM 2100x
2026-03-30 11:28:25 -04:00

44 lines
1.6 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000804
# UNDF: (leave blank)
# scribus-0003: Selection::addItems m_SelList.contains O(N×M)
#
# In scribus/selection.cpp, addItems() iterates over the items to add (N) and
# for each calls m_SelList.contains(item), which is O(M) on the existing
# QList<QPointer<PageItem>> selection list. Total: O(N×M). For a "Select All"
# on a 5000-item document adding to an existing selection of 2000, this is
# ~10M pointer comparisons.
#
# The single-item addItem() also calls m_SelList.contains(item) — O(M) per
# call — but is less severe since it adds one item at a time.
#
# Fix: build a QSet<PageItem*> from m_SelList before the loop for O(1) lookup,
# or maintain a companion QSet as a class member.
#
# Severity: MEDIUM — triggered on every multi-select operation (rubber-band,
# Select All, group selection); scales with document item count.
--- a/scribus/selection.cpp
+++ b/scribus/selection.cpp
@@ -194,6 +194,12 @@
bool Selection::addItems(const QList<PageItem *>& items)
{
if (items.isEmpty())
return false;
+ // Build hash set for O(1) membership check instead of O(M) QList::contains
+ QSet<PageItem*> existing;
+ existing.reserve(m_SelList.count());
+ for (int i = 0; i < m_SelList.count(); ++i)
+ existing.insert(m_SelList.at(i).data());
+
QList< QPointer<PageItem> > toAdd;
toAdd.reserve(items.count());
for (int i = 0; i < items.count(); ++i)
{
PageItem* item = items.at(i);
- if (m_SelList.contains(item))
+ if (existing.contains(item))
continue;
toAdd.append(item);
+ existing.insert(item);
item->setSelected(true);
}