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
75 lines
2.3 KiB
Diff
75 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000000802
|
|
# UNDF: (leave blank)
|
|
# scribus-0001: getSortedStyleList retList.contains O(N²) dedup
|
|
#
|
|
# In scribus/scribusdoc.cpp, four identical functions — getSortedStyleList(),
|
|
# getSortedCharStyleList(), getSortedTableStyleList(), getSortedCellStyleList()
|
|
# — walk the style parent chain and accumulate indices into retList using
|
|
# QList<int>::contains() to dedup. QList::contains is O(N) per call, and the
|
|
# outer loop is O(N) over all styles, making overall complexity O(N²).
|
|
#
|
|
# Additionally, the inner while-loop walking up the parent chain accumulates
|
|
# into retList2 with retList2.contains(pp) — a minor O(depth²) per style.
|
|
#
|
|
# For a document with N=500 paragraph styles (plausible in long-form publishing
|
|
# with inherited house styles), this is ~125,000 linear scans instead of ~500
|
|
# hash lookups.
|
|
#
|
|
# Fix: maintain a companion QSet<int> for O(1) membership test alongside the
|
|
# ordered QList<int> retList.
|
|
#
|
|
# Severity: MEDIUM — 4 identical defect sites; triggered on style
|
|
# reorder/display; scales with style count.
|
|
--- a/scribus/scribusdoc.cpp
|
|
+++ b/scribus/scribusdoc.cpp
|
|
@@ -1198,6 +1198,7 @@
|
|
QList<int> ScribusDoc::getSortedStyleList() const
|
|
{
|
|
QList<int> retList;
|
|
+ QSet<int> retSet;
|
|
for (int i = 0; i < m_docParagraphStyles.count(); ++i)
|
|
{
|
|
if (m_docParagraphStyles[i].parent().isEmpty())
|
|
{
|
|
- if (!retList.contains(i))
|
|
+ if (!retSet.contains(i))
|
|
+ {
|
|
retList.append(i);
|
|
+ retSet.insert(i);
|
|
+ }
|
|
continue;
|
|
}
|
|
|
|
QList<int> retList2;
|
|
+ QSet<int> retSet2;
|
|
...
|
|
retList2.prepend(i);
|
|
+ retSet2.insert(i);
|
|
while ((!par.isEmpty()) && (par != name))
|
|
{
|
|
int pp = m_docParagraphStyles.find(par);
|
|
- if ((pp >= 0) && (!retList2.contains(pp)))
|
|
+ if ((pp >= 0) && (!retSet2.contains(pp)))
|
|
+ {
|
|
retList2.prepend(pp);
|
|
+ retSet2.insert(pp);
|
|
+ }
|
|
par = (pp >= 0) ? m_docParagraphStyles[pp].parent() : QString();
|
|
}
|
|
for (int r = 0; r < retList2.count(); ++r)
|
|
{
|
|
- if (!retList.contains(retList2[r]))
|
|
+ if (!retSet.contains(retList2[r]))
|
|
+ {
|
|
retList.append(retList2[r]);
|
|
+ retSet.insert(retList2[r]);
|
|
+ }
|
|
}
|
|
}
|
|
return retList;
|
|
}
|
|
|
|
// Same fix applies identically to:
|
|
// getSortedCharStyleList() (line 1230)
|
|
// getSortedTableStyleList() (line 1262)
|
|
// getSortedCellStyleList() (line 1294)
|