Fix OOB access while dumping struct layout for invalid storage class layout

A one letter typo would lead to invalid memory access in the very
specific case of outputting the layout for a struct within a struct with
field alignment padding, and the inner struct has more members than the
outer.

Bug: tint:1344
Bug: oss-fuzz:72642
Change-Id: I749e3fb172e78a20ece68b40be1a0a57dc5746f4
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/72642
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/resolver/resolver_validation.cc b/src/resolver/resolver_validation.cc
index 6921a51..117eb25 100644
--- a/src/resolver/resolver_validation.cc
+++ b/src/resolver/resolver_validation.cc
@@ -263,7 +263,8 @@
 
   // TODO(amaiorano): Output struct and member decorations so that this output
   // can be copied verbatim back into source
-  auto get_struct_layout_string = [&](const sem::Struct* st) -> std::string {
+  auto get_struct_layout_string = [this, member_name_of, type_name_of](
+                                      const sem::Struct* st) -> std::string {
     std::stringstream ss;
 
     if (st->Members().empty()) {
@@ -308,7 +309,7 @@
       auto* const m = st->Members()[i];
 
       // Output field alignment padding, if any
-      auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
+      auto* const prev_member = (i == 0) ? nullptr : st->Members()[i - 1];
       if (prev_member) {
         uint32_t padding =
             m->Offset() - (prev_member->Offset() + prev_member->Size());
diff --git a/src/resolver/storage_class_layout_validation_test.cc b/src/resolver/storage_class_layout_validation_test.cc
index 3ad7d3f..467608d 100644
--- a/src/resolver/storage_class_layout_validation_test.cc
+++ b/src/resolver/storage_class_layout_validation_test.cc
@@ -263,6 +263,63 @@
 22:24 note: see declaration of variable)");
 }
 
+// See https://crbug.com/tint/1344
+TEST_F(ResolverStorageClassLayoutValidationTest,
+       UniformBuffer_MembersOffsetNotMultipleOf16_InnerMoreMembersThanOuter) {
+  // struct Inner {
+  //   a : i32;
+  //   b : i32;
+  //   c : i32;
+  //   [[align(1), size(5)]] scalar : i32;
+  // };
+  //
+  // [[block]]
+  // struct Outer {
+  //   inner : Inner;
+  //   scalar : i32;
+  // };
+  //
+  // [[group(0), binding(0)]]
+  // var<uniform> a : Outer;
+
+  Structure(Source{{12, 34}}, "Inner",
+            {
+                Member("a", ty.i32()),
+                Member("b", ty.i32()),
+                Member("c", ty.i32()),
+                Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)}),
+            });
+
+  Structure(Source{{34, 56}}, "Outer",
+            {
+                Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
+                Member(Source{{78, 90}}, "scalar", ty.i32()),
+            },
+            {StructBlock()});
+
+  Global(Source{{22, 24}}, "a", ty.type_name("Outer"),
+         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+
+  ASSERT_FALSE(r()->Resolve());
+  EXPECT_EQ(
+      r()->error(),
+      R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting [[align(16)]] on this member
+34:56 note: see layout of struct:
+/*            align(4) size(24) */ struct Outer {
+/* offset( 0) align(4) size(20) */   inner : Inner;
+/* offset(20) align(4) size( 4) */   scalar : i32;
+/*                              */ };
+12:34 note: and layout of previous member struct:
+/*            align(4) size(20) */ struct Inner {
+/* offset( 0) align(4) size( 4) */   a : i32;
+/* offset( 4) align(4) size( 4) */   b : i32;
+/* offset( 8) align(4) size( 4) */   c : i32;
+/* offset(12) align(1) size( 5) */   scalar : i32;
+/* offset(17) align(1) size( 3) */   // -- implicit struct size padding --;
+/*                              */ };
+22:24 note: see declaration of variable)");
+}
+
 TEST_F(ResolverStorageClassLayoutValidationTest,
        UniformBuffer_MembersOffsetNotMultipleOf16_SuggestedFix) {
   // struct Inner {