summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Boeckel <ben.boeckel@kitware.com>2019-11-20 16:00:37 -0500
committerBen Boeckel <ben.boeckel@kitware.com>2019-11-20 16:00:37 -0500
commitebbb9e2fdb0746e2125013e29a334efc8c0331b6 (patch)
tree5b01bde0221830090dd6aaf986142c71835ab341
parent1daa7470ab7ed147726b560d0bc55327fff3482f (diff)
downloadninja-ebbb9e2fdb0746e2125013e29a334efc8c0331b6.tar.gz
depfile_parser_test: test buggy -MP behavior
This ensures the current behavior of rejecting this case due to `x` being reused as an input.
-rw-r--r--src/depfile_parser.cc12
-rw-r--r--src/depfile_parser.in.cc12
-rw-r--r--src/depfile_parser_test.cc9
3 files changed, 31 insertions, 2 deletions
diff --git a/src/depfile_parser.cc b/src/depfile_parser.cc
index e92584e..90d4a8a 100644
--- a/src/depfile_parser.cc
+++ b/src/depfile_parser.cc
@@ -51,6 +51,7 @@ bool DepfileParser::Parse(string* content, string* err) {
char* end = in + content->size();
bool have_target = false;
bool parsing_targets = true;
+ bool poisoned_input = false;
while (in < end) {
bool have_newline = false;
// out: current output point (typically same as in, but can fall behind
@@ -295,8 +296,13 @@ yy28:
if (len > 0) {
StringPiece piece = StringPiece(filename, len);
// If we've seen this as an input before, skip it.
- if (std::find(ins_.begin(), ins_.end(), piece) == ins_.end()) {
+ std::vector<StringPiece>::iterator pos = std::find(ins_.begin(), ins_.end(), piece);
+ if (pos == ins_.end()) {
if (is_dependency) {
+ if (poisoned_input) {
+ *err = "inputs may not also have inputs";
+ return false;
+ }
// New input.
ins_.push_back(piece);
} else {
@@ -304,12 +310,16 @@ yy28:
if (std::find(outs_.begin(), outs_.end(), piece) == outs_.end())
outs_.push_back(piece);
}
+ } else if (!is_dependency) {
+ // We've passed an input on the left side; reject new inputs.
+ poisoned_input = true;
}
}
if (have_newline) {
// A newline ends a rule so the next filename will be a new target.
parsing_targets = true;
+ poisoned_input = false;
}
}
if (!have_target) {
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
index eba892f..b32b942 100644
--- a/src/depfile_parser.in.cc
+++ b/src/depfile_parser.in.cc
@@ -50,6 +50,7 @@ bool DepfileParser::Parse(string* content, string* err) {
char* end = in + content->size();
bool have_target = false;
bool parsing_targets = true;
+ bool poisoned_input = false;
while (in < end) {
bool have_newline = false;
// out: current output point (typically same as in, but can fall behind
@@ -147,8 +148,13 @@ bool DepfileParser::Parse(string* content, string* err) {
if (len > 0) {
StringPiece piece = StringPiece(filename, len);
// If we've seen this as an input before, skip it.
- if (std::find(ins_.begin(), ins_.end(), piece) == ins_.end()) {
+ std::vector<StringPiece>::iterator pos = std::find(ins_.begin(), ins_.end(), piece);
+ if (pos == ins_.end()) {
if (is_dependency) {
+ if (poisoned_input) {
+ *err = "inputs may not also have inputs";
+ return false;
+ }
// New input.
ins_.push_back(piece);
} else {
@@ -156,12 +162,16 @@ bool DepfileParser::Parse(string* content, string* err) {
if (std::find(outs_.begin(), outs_.end(), piece) == outs_.end())
outs_.push_back(piece);
}
+ } else if (!is_dependency) {
+ // We've passed an input on the left side; reject new inputs.
+ poisoned_input = true;
}
}
if (have_newline) {
// A newline ends a rule so the next filename will be a new target.
parsing_targets = true;
+ poisoned_input = false;
}
}
if (!have_target) {
diff --git a/src/depfile_parser_test.cc b/src/depfile_parser_test.cc
index e5e3038..bf1a0bc 100644
--- a/src/depfile_parser_test.cc
+++ b/src/depfile_parser_test.cc
@@ -332,3 +332,12 @@ TEST_F(DepfileParserTest, MultipleRulesDifferentOutputs) {
EXPECT_EQ("y", parser_.ins_[1].AsString());
EXPECT_EQ("z", parser_.ins_[2].AsString());
}
+
+TEST_F(DepfileParserTest, BuggyMP) {
+ std::string err;
+ EXPECT_FALSE(Parse("foo: x y z\n"
+ "x: alsoin\n"
+ "y:\n"
+ "z:\n", &err));
+ ASSERT_EQ("inputs may not also have inputs", err);
+}