# UNDF: UNDF-2026-000000723 --- a/src/graph.cc +++ b/src/graph.cc @@ -15,6 +15,7 @@ #include "graph.h" #include +#include #include #include #include @@ -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::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 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::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);