From 29f373a66bb9d3c56a1d4cf476832c12b7e2e1ad Mon Sep 17 00:00:00 2001
From: Nico Weber <nicolasweber@gmx.de>
Date: Tue, 26 Apr 2016 21:55:20 -0400
Subject: Fix crash with duplicate implicit outputs.

Sadly, duplicate outputs aren't an error by default in Ninja (see also
a new edge has no effect.  Remember to decrement the "number of
implicit outputs" counter for the new edge when this happens.

Fixes #1136.
---
 src/manifest_parser.cc      | 18 +++++++++++-------
 src/manifest_parser_test.cc | 24 ++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc
index be267a3..a4f489e 100644
--- a/src/manifest_parser.cc
+++ b/src/manifest_parser.cc
@@ -339,8 +339,8 @@ bool ManifestParser::ParseEdge(string* err) {
   }
 
   edge->outputs_.reserve(outs.size());
-  for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) {
-    string path = i->Evaluate(env);
+  for (size_t i = 0, e = outs.size(); i != e; ++i) {
+    string path = outs[i].Evaluate(env);
     string path_err;
     unsigned int slash_bits;
     if (!CanonicalizePath(&path, &slash_bits, &path_err))
@@ -350,11 +350,15 @@ bool ManifestParser::ParseEdge(string* err) {
         lexer_.Error("multiple rules generate " + path + " [-w dupbuild=err]",
                      err);
         return false;
-      } else if (!quiet_) {
-        Warning("multiple rules generate %s. "
-                "builds involving this target will not be correct; "
-                "continuing anyway [-w dupbuild=warn]",
-                path.c_str());
+      } else {
+        if (!quiet_) {
+          Warning("multiple rules generate %s. "
+                  "builds involving this target will not be correct; "
+                  "continuing anyway [-w dupbuild=warn]",
+                  path.c_str());
+        }
+        if (e - i <= static_cast<size_t>(implicit_outs))
+          --implicit_outs;
       }
     }
   }
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
index ba83a67..1312d26 100644
--- a/src/manifest_parser_test.cc
+++ b/src/manifest_parser_test.cc
@@ -949,6 +949,30 @@ TEST_F(ParserTest, ImplicitOutputEmpty) {
   EXPECT_FALSE(edge->is_implicit_out(0));
 }
 
+TEST_F(ParserTest, ImplicitOutputDupe) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(
+"rule cat\n"
+"  command = cat $in > $out\n"
+"build foo baz | foo baq foo: cat bar\n"));
+
+  Edge* edge = state.LookupNode("foo")->in_edge();
+  ASSERT_EQ(edge->outputs_.size(), 3);
+  EXPECT_FALSE(edge->is_implicit_out(0));
+  EXPECT_FALSE(edge->is_implicit_out(1));
+  EXPECT_TRUE(edge->is_implicit_out(2));
+}
+
+TEST_F(ParserTest, ImplicitOutputDupes) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(
+"rule cat\n"
+"  command = cat $in > $out\n"
+"build foo foo foo | foo foo foo foo: cat bar\n"));
+
+  Edge* edge = state.LookupNode("foo")->in_edge();
+  ASSERT_EQ(edge->outputs_.size(), 1);
+  EXPECT_FALSE(edge->is_implicit_out(0));
+}
+
 TEST_F(ParserTest, NoExplicitOutput) {
   ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
   string err;
-- 
cgit v0.12