java-topology/defects/ninja/patch/ninja-0002-graph-output-set.patch
russell@unturf.com f176e86fbd ninja-0001/ninja-0002: CWE-407 depfile dedup and output validation O(N²)→O(N)
ninja-0001: depfile_parser.cc std::find over ins_/outs_ vectors is O(N) per
token → O(N²) total parse; fix adds unordered_set ins_seen_/outs_seen_ members
to DepfileParser for O(1) duplicate detection (490x at N=1000).

ninja-0002: graph.cc std::find_if over edge->outputs_ called for each depfile
output token is O(M×N); fix builds unordered_set from edge outputs once before
the loop for O(M+N) total (125x at M=N=500).
2026-03-30 06:56:54 -04:00

42 lines
1.6 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000723
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -15,6 +15,7 @@
#include "graph.h"
#include <algorithm>
+#include <unordered_set>
#include <deque>
#include <assert.h>
#include <stdio.h>
@@ -706,13 +706,20 @@ bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path,
return false;
}
- // Ensure that all mentioned outputs are outputs of the edge.
- for (std::vector<StringPiece>::iterator o = depfile.outs_.begin();
- o != depfile.outs_.end(); ++o) {
- matches m(o);
- if (std::find_if(edge->outputs_.begin(), edge->outputs_.end(), m) == edge->outputs_.end()) {
- *err = path + ": depfile mentions '" + o->AsString() + "' as an output, but no such output was declared";
- return false;
- }
+ // CWE-407 fix: build an O(1) lookup set from edge outputs once, then
+ // validate each depfile output in O(1). The original code was O(M×N)
+ // where M = depfile outs and N = edge outputs; with multiple-output edges
+ // (e.g. unity builds) both dimensions can be large.
+ std::unordered_set<std::string> output_paths;
+ output_paths.reserve(edge->outputs_.size());
+ for (const Node* out : edge->outputs_) {
+ output_paths.insert(out->path());
+ }
+ // Ensure that all mentioned outputs are outputs of the edge.
+ for (std::vector<StringPiece>::iterator o = depfile.outs_.begin();
+ o != depfile.outs_.end(); ++o) {
+ if (output_paths.find(o->AsString()) == output_paths.end()) {
+ *err = path + ": depfile mentions '" + o->AsString() + "' as an output, but no such output was declared";
+ return false;
+ }
}
return ProcessDepfileDeps(edge, &depfile.ins_, err);