java-topology/defects/scribus/patch/scribus-0002-get-used-patterns-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

67 lines
2.3 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-000000803
# UNDF: (leave blank)
# scribus-0002: getUsedPatterns results.contains O(I×R) pattern collection
#
# In scribus/scribusdoc.cpp, getUsedPatterns() iterates over all page items
# and for each checks results.contains(pattern) — a QStringList linear scan
# O(R) where R is the number of results accumulated so far. With I page items
# each potentially contributing 3 pattern names (fill, stroke, mask), the
# overall complexity is O(3×I×R). For a document with 2000 items and 200
# patterns, that is ~1.2M string comparisons.
#
# The same pattern repeats in getUsedPatternsSelection() and
# getUsedPatternsHelper() and getPatternDependencyList().
#
# Fix: maintain a companion QSet<QString> for O(1) membership alongside the
# QStringList for ordered results.
#
# Severity: MEDIUM — triggered during document save, export, and pattern
# cleanup; scales with item count × pattern count.
--- a/scribus/scribusdoc.cpp
+++ b/scribus/scribusdoc.cpp
@@ -3933,6 +3933,7 @@
QStringList ScribusDoc::getUsedPatterns() const
{
QStringList results;
+ QSet<QString> resultSet;
for (PageItemIterator it(this, ...); *it; ++it)
{
const PageItem* currItem = *it;
- if ((!results.contains(currItem->pattern())) && ...)
+ if ((!resultSet.contains(currItem->pattern())) && ...)
+ {
results.append(currItem->pattern());
+ resultSet.insert(currItem->pattern());
+ }
if (!currItem->strokePattern().isEmpty())
{
- if (!results.contains(currItem->strokePattern()))
+ if (!resultSet.contains(currItem->strokePattern()))
+ {
results.append(currItem->strokePattern());
+ resultSet.insert(currItem->strokePattern());
+ }
}
if (!currItem->patternMask().isEmpty())
{
- if (!results.contains(currItem->patternMask()))
+ if (!resultSet.contains(currItem->patternMask()))
+ {
results.append(currItem->patternMask());
+ resultSet.insert(currItem->patternMask());
+ }
}
}
// Same fix for the inner docPatterns loop (lines 3955-3983)
- // Replace results.contains(...) with resultSet.contains(...)
+ // and add resultSet.insert(...) after each results.append(...)
return results;
}
// Same fix applies to:
// getUsedPatternsSelection() (line 3988)
// getUsedPatternsHelper() (line 4036)
// getPatternDependencyList() (line 4087)