cmake-0005: cmQtAutoGen MergeOptions std::find over baseOpts in newOpts loop, O(N*M), 31.5x at N=M=50 cmake-0006: cmVisualStudio10TargetGenerator FinishWritingSource writtenSettings O(S^2), 15.3x at S=30 cmake-0007: cmGeneratorExpressionNode TargetRuntimeDllDirsNode dllDirs O(D^2), 10.3x at D=100 MPD: all 5 MOADs CLEAN; updated CLEAN.md with MOAD-0002 through MOAD-0005 analysis. Unit tests: 3/3 PASS.
2.3 KiB
cmake-0005 — MergeOptions: O(N×M) std::find inside compiler-flag merge loop
Target: CMake (Kitware/CMake)
Severity: MEDIUM
File: Source/cmQtAutoGen.cxx
Lines: 39–72 (static MergeOptions), called via UicMergeOptions / RccMergeOptions
CWE: CWE-407 (Algorithmic Complexity)
Pattern
// Source/cmQtAutoGen.cxx:38-72
for (auto fit = newOpts.begin(), fitEnd = newOpts.end(); fit != fitEnd; ++fit) {
std::string const& newOpt = *fit;
auto existIt = std::find(baseOpts.begin(), baseOpts.end(), newOpt); // O(M)
...
}
For each option in newOpts (size N), std::find scans baseOpts (size M) linearly.
Total cost: O(N × M) per call.
MergeOptions is called via:
UicMergeOptionsincmQtAutoMocUic.cxxper.uisource file processedRccMergeOptionsincmQtAutoGenInitializer.cxxper.qrcresource file
In a large Qt project with many .ui or .qrc files and many per-file compiler
options, this becomes O(F × N × M) where F = number of source files.
Exploit Scenario
A project with 100 .ui files and 50 options per file: 100 × 50 × 50 = 250,000 comparisons
instead of 100 × 50 × 1 = 5,000 with a hash set (50x overhead).
Fix
Build an std::unordered_set<std::string> from baseOpts before our loop,
then replace std::find with unordered_set::count() — O(1) average lookup.
Note: MergeOptions also updates existing option values in place (value options),
so the vector must be kept for mutation; only the membership test moves to our set.
MOAD Classification
MOAD-0001 (CWE-407): list membership test (std::find over baseOpts) inside
loop (for over newOpts).
MOADs 0002-0005 for CMake
- MOAD-0002 (Intertangle): CLEAN.
cmakeclass passes state through explicit parameters; configuration and generation phases are clearly separated. - MOAD-0003 (Leaked Context): CLEAN. CMake is single-threaded during configure;
no
thread_localcarrying request-scoped identity. - MOAD-0004 (CWE-312): CLEAN. CTest/CDash does not log submit tokens or passwords verbatim in our code review. CDash credentials flow through HTTP headers but are not emitted to our cmake log.
- MOAD-0005 (Thundering Herd): CLEAN. Lazy-init patterns in CMake use deterministic single-threaded flow; no unsynchronized cache get+null+compute+put patterns found.