diff options
author | Nico Weber <nicolasweber@gmx.de> | 2015-03-21 15:28:59 (GMT) |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2015-03-21 15:28:59 (GMT) |
commit | da1be5ece1f164ec6087aafe4efb0084c474afea (patch) | |
tree | d0fec490d0f5a3fbd930c70067a89eff4e619236 | |
parent | 403c9194af07f11a14a5d8416b6eaf4ad7b84a7e (diff) | |
parent | 9aab00003c62f8d6b8142e6ecfe8f0aeefc81f74 (diff) | |
download | Ninja-da1be5ece1f164ec6087aafe4efb0084c474afea.zip Ninja-da1be5ece1f164ec6087aafe4efb0084c474afea.tar.gz Ninja-da1be5ece1f164ec6087aafe4efb0084c474afea.tar.bz2 |
Merge pull request #942 from nico/cyclefix2
Don't crash on cyclic references between rule bindings.
-rw-r--r-- | src/graph.cc | 22 | ||||
-rw-r--r-- | src/manifest_parser.cc | 2 |
2 files changed, 23 insertions, 1 deletions
diff --git a/src/graph.cc b/src/graph.cc index b19dc85..d99c8bd 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -217,7 +217,7 @@ struct EdgeEnv : public Env { enum EscapeKind { kShellEscape, kDoNotEscape }; EdgeEnv(Edge* edge, EscapeKind escape) - : edge_(edge), escape_in_out_(escape) {} + : edge_(edge), escape_in_out_(escape), recursive_(false) {} virtual string LookupVariable(const string& var); /// Given a span of Nodes, construct a list of paths suitable for a command @@ -226,8 +226,11 @@ struct EdgeEnv : public Env { vector<Node*>::iterator end, char sep); + private: + vector<string> lookups_; Edge* edge_; EscapeKind escape_in_out_; + bool recursive_; }; string EdgeEnv::LookupVariable(const string& var) { @@ -243,8 +246,25 @@ string EdgeEnv::LookupVariable(const string& var) { ' '); } + if (recursive_) { + vector<string>::const_iterator it; + if ((it = find(lookups_.begin(), lookups_.end(), var)) != lookups_.end()) { + string cycle; + for (; it != lookups_.end(); ++it) + cycle.append(*it + " -> "); + cycle.append(var); + Fatal(("cycle in rule variables: " + cycle).c_str()); + } + } + // See notes on BindingEnv::LookupWithFallback. const EvalString* eval = edge_->rule_->GetBinding(var); + if (recursive_ && eval) + lookups_.push_back(var); + + // In practice, variables defined on rules never use another rule variable. + // For performance, only start checking for cycles after the first lookup. + recursive_ = true; return edge_->env_->LookupWithFallback(var, eval, this); } diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc index 4e639d1..b747ad4 100644 --- a/src/manifest_parser.cc +++ b/src/manifest_parser.cc @@ -321,6 +321,7 @@ bool ManifestParser::ParseEdge(string* err) { edge->pool_ = pool; } + edge->outputs_.reserve(outs.size()); for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) { string path = i->Evaluate(env); string path_err; @@ -337,6 +338,7 @@ bool ManifestParser::ParseEdge(string* err) { return true; } + edge->inputs_.reserve(ins.size()); for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) { string path = i->Evaluate(env); string path_err; |