[tint] Fix UB in FileContent copy constructor

Calling `front()` on an empty string_view is undefined behavior, and
crashes on macOS. This only affects our benchmarks.

Change-Id: I5342833bc0b0d7ad5ce494c9776c0ba4118699f1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/196094
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/utils/diagnostic/source.cc b/src/tint/utils/diagnostic/source.cc
index 8f07d77..8b036e8 100644
--- a/src/tint/utils/diagnostic/source.cc
+++ b/src/tint/utils/diagnostic/source.cc
@@ -118,6 +118,9 @@
                                                       const std::string_view& dst_view) {
     std::vector<std::string_view> out(src_list.size());
     for (size_t i = 0; i < src_list.size(); i++) {
+        if (src_list[i].empty()) {
+            continue;
+        }
         auto offset = static_cast<size_t>(&src_list[i].front() - &src_view.front());
         auto count = src_list[i].length();
         out[i] = dst_view.substr(offset, count);
diff --git a/src/tint/utils/diagnostic/source_test.cc b/src/tint/utils/diagnostic/source_test.cc
index b15eafb..4c9df84 100644
--- a/src/tint/utils/diagnostic/source_test.cc
+++ b/src/tint/utils/diagnostic/source_test.cc
@@ -37,8 +37,10 @@
 namespace tint {
 namespace {
 
+// Include a blank line to test that empty strings are handled correctly.
 static constexpr std::string_view kSource = R"(line one
 line two
+
 line three)";
 
 using SourceFileContentTest = testing::Test;
@@ -46,10 +48,11 @@
 TEST_F(SourceFileContentTest, Init) {
     Source::FileContent fc(kSource);
     EXPECT_EQ(fc.data, kSource);
-    ASSERT_EQ(fc.lines.size(), 3u);
+    ASSERT_EQ(fc.lines.size(), 4u);
     EXPECT_EQ(fc.lines[0], "line one");
     EXPECT_EQ(fc.lines[1], "line two");
-    EXPECT_EQ(fc.lines[2], "line three");
+    EXPECT_EQ(fc.lines[2], "");
+    EXPECT_EQ(fc.lines[3], "line three");
 }
 
 TEST_F(SourceFileContentTest, CopyInit) {
@@ -57,10 +60,11 @@
     Source::FileContent fc{*src};
     src.reset();
     EXPECT_EQ(fc.data, kSource);
-    ASSERT_EQ(fc.lines.size(), 3u);
+    ASSERT_EQ(fc.lines.size(), 4u);
     EXPECT_EQ(fc.lines[0], "line one");
     EXPECT_EQ(fc.lines[1], "line two");
-    EXPECT_EQ(fc.lines[2], "line three");
+    EXPECT_EQ(fc.lines[2], "");
+    EXPECT_EQ(fc.lines[3], "line three");
 }
 
 TEST_F(SourceFileContentTest, MoveInit) {
@@ -68,10 +72,11 @@
     Source::FileContent fc{std::move(*src)};
     src.reset();
     EXPECT_EQ(fc.data, kSource);
-    ASSERT_EQ(fc.lines.size(), 3u);
+    ASSERT_EQ(fc.lines.size(), 4u);
     EXPECT_EQ(fc.lines[0], "line one");
     EXPECT_EQ(fc.lines[1], "line two");
-    EXPECT_EQ(fc.lines[2], "line three");
+    EXPECT_EQ(fc.lines[2], "");
+    EXPECT_EQ(fc.lines[3], "line three");
 }
 
 // Line break code points