summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2015-03-21 08:28:59 -0700
committerNico Weber <nicolasweber@gmx.de>2015-03-21 08:28:59 -0700
commitda1be5ece1f164ec6087aafe4efb0084c474afea (patch)
treed0fec490d0f5a3fbd930c70067a89eff4e619236
parent403c9194af07f11a14a5d8416b6eaf4ad7b84a7e (diff)
parent9aab00003c62f8d6b8142e6ecfe8f0aeefc81f74 (diff)
downloadninja-da1be5ece1f164ec6087aafe4efb0084c474afea.tar.gz
Merge pull request #942 from nico/cyclefix2
Don't crash on cyclic references between rule bindings.
-rw-r--r--src/graph.cc22
-rw-r--r--src/manifest_parser.cc2
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;