# UNDF: UNDF-2026-000000054 --- a/Source/Dry/UI/ListView.h +++ b/Source/Dry/UI/ListView.h @@ -... ListView class members - PODVector selections_; + PODVector selections_; // preserved for ordered iteration + HashSet 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& 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 indicesSet(indices.Begin(), indices.End()); + // Remove first items that should no longer be selected for (PODVector::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::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()