diff options
author | Nico Weber <nicolasweber@gmx.de> | 2015-03-18 16:54:16 -0400 |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2015-03-21 08:15:41 -0700 |
commit | eb7167d456b8ef2dad3846ca2ba6438b060518c9 (patch) | |
tree | 041c666e665178ba6a8db7235f8dc697d9ceafc7 | |
parent | 403c9194af07f11a14a5d8416b6eaf4ad7b84a7e (diff) | |
download | ninja-eb7167d456b8ef2dad3846ca2ba6438b060518c9.tar.gz |
Don't crash on cyclic references between rule bindings.
Fixes #902.
This dynamically detects cycles. I like this approach less than
detecting them statically when parsing rules [1], but it has the
advantage that it doesn't break existing ninja manifest files.
It has the disadvantage that it slows down manifest_parser_perftest by
3.9%.
1: https://github.com/martine/ninja/commit/cc6f54d6d436047
-rw-r--r-- | src/graph.cc | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/src/graph.cc b/src/graph.cc index b19dc85..41055ec 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -226,6 +226,7 @@ struct EdgeEnv : public Env { vector<Node*>::iterator end, char sep); + vector<string> lookups_; Edge* edge_; EscapeKind escape_in_out_; }; @@ -243,8 +244,19 @@ string EdgeEnv::LookupVariable(const string& var) { ' '); } + 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 (eval) + lookups_.push_back(var); return edge_->env_->LookupWithFallback(var, eval, this); } |