summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2015-03-18 16:54:16 -0400
committerNico Weber <nicolasweber@gmx.de>2015-03-21 08:15:41 -0700
commiteb7167d456b8ef2dad3846ca2ba6438b060518c9 (patch)
tree041c666e665178ba6a8db7235f8dc697d9ceafc7
parent403c9194af07f11a14a5d8416b6eaf4ad7b84a7e (diff)
downloadninja-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.cc12
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);
}