java-topology/defects/dry/patch/dry-0001-listview-hashset.patch

60 lines
2.3 KiB
Diff

# UNDF: UNDF-2026-000000054
--- a/Source/Dry/UI/ListView.h
+++ b/Source/Dry/UI/ListView.h
@@ -... ListView class members
- PODVector<unsigned> selections_;
+ PODVector<unsigned> selections_; // preserved for ordered iteration
+ HashSet<unsigned> selections_set_; // O(1) shadow index for Contains checks
--- a/Source/Dry/UI/ListView.cpp
+++ b/Source/Dry/UI/ListView.cpp
@@ -518,7 +518,8 @@ void ListView::SetSelections(const PODVector<unsigned>& indices)
unsigned numItems = GetNumItems();
+ // FIX dry-0001: build O(1) lookup set from incoming indices — CWE-407
+ // Both loops below called indices.Contains() or selections_.Contains() which are
+ // O(n) linear scans on PODVector. At k=1000 selections: O(n²) = 1,000,000 ops.
+ HashSet<unsigned> indicesSet(indices.Begin(), indices.End());
+
// Remove first items that should no longer be selected
for (PODVector<unsigned>::Iterator i = selections_.Begin(); i != selections_.End();)
{
unsigned index = *i;
- if (!indices.Contains(index)) // O(n) — CWE-407
+ if (!indicesSet.Contains(index)) // O(1) — fixed
{
i = selections_.Erase(i);
+ selections_set_.Erase(index);
using namespace ItemSelected;
// ... SendEvent(E_ITEMDESELECTED, ...)
}
else
++i;
}
// Then add missing items
for (PODVector<unsigned>::ConstIterator i = indices.Begin(); i != indices.End(); ++i)
{
unsigned index = *i;
if (index < numItems)
{
- bool duplicate = selections_.Contains(index); // O(n) — CWE-407
+ bool duplicate = selections_set_.Contains(index); // O(1) — fixed
if (!duplicate || !multiselect_)
{
if (!duplicate)
{
selections_.Push(index);
+ selections_set_.Insert(index);
added = true;
}
}
}
}
}
// All other methods that modify selections_ must also maintain selections_set_:
// AddSelection(index) → selections_set_.Insert(index)
// RemoveSelection(index) → selections_set_.Erase(index)
// ClearSelection() → selections_set_.Clear()