java-topology/defects/cmake-0005/SCAN-NOTES.md
russell@unturf.com fb1ff685c1 cmake+mpd: 5-MOAD scan; 3 new CWE-407 defects, MPD CLEAN all 5 MOADs
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.
2026-03-31 22:31:15 -04:00

2.3 KiB
Raw Blame History

cmake-0005 — MergeOptions: O(N×M) std::find inside compiler-flag merge loop

Target: CMake (Kitware/CMake) Severity: MEDIUM File: Source/cmQtAutoGen.cxx Lines: 3972 (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:

  • UicMergeOptions in cmQtAutoMocUic.cxx per .ui source file processed
  • RccMergeOptions in cmQtAutoGenInitializer.cxx per .qrc resource 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. cmake class 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_local carrying 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.