# UNDF: UNDF-2026-000000703 # UNDF: (leave blank) # Audacity CWE-407: WaveTrack::CanOffsetClips() O(I*M) moving clip scan # # In au3/libraries/au3-wave-track/WaveTrack.cpp, CanOffsetClips() iterates # over all intervals and for each one checks whether it's in the movingClips # vector via std::find(). The source code itself acknowledges this: # "linear search might be improved, but expecting few moving clips" # # This is O(I*M) where I=total intervals (clips) and M=moving clips. # In projects with many clips per track (podcast editing, sample slicing, # beat detection results), both I and M can be large. # # Fix: build an unordered_set from movingClips before the loop # for O(1) membership test. # # Severity: MEDIUM — triggered during every clip drag/offset operation. # At I=200 clips, M=50 moving: 10,000 comparisons reduced to 200. --- a/au3/libraries/au3-wave-track/WaveTrack.cpp +++ b/au3/libraries/au3-wave-track/WaveTrack.cpp @@ -3186,10 +3186,9 @@ *allowedAmount = amount; } - const auto& moving = [&](Interval* clip){ - // linear search might be improved, but expecting few moving clips - // compared with the fixed clips - return movingClips.end() - != std::find(movingClips.begin(), movingClips.end(), clip); - }; + // Use a set for O(1) membership test instead of O(M) linear search + std::unordered_set movingSet(movingClips.begin(), movingClips.end()); + const auto& moving = [&](Interval* clip){ + return movingSet.count(clip) > 0; + }; for (const auto& c: Intervals()) { if (moving(c.get())) {