[fidl] Fix decode/validate crash in case of tables of (nested) arrays of
primitives.

With the introduction of coding tables for boring types inside FIDL tables
to support linearization, array coding tables may have a null element,
when the array is in a FIDL table but the element is a boring type.

TEST: fx run-host-tests fidl_cpp_unittests
Change-Id: I56380c36369e4b501f5b82aa9cfc673c564f82a1
diff --git a/sdk/lib/fidl/cpp/fidl_test.test.fidl b/sdk/lib/fidl/cpp/fidl_test.test.fidl
index a693aeb..63173a2 100644
--- a/sdk/lib/fidl/cpp/fidl_test.test.fidl
+++ b/sdk/lib/fidl/cpp/fidl_test.test.fidl
@@ -89,3 +89,9 @@
     2: SampleXUnion xu;
     3: string after;
 };
+
+table PrimitiveArrayInTable {
+    1: string before;
+    2: array<int32>:9 arr;
+    3: string after;
+};
diff --git a/sdk/lib/fidl/cpp/roundtrip_test.cc b/sdk/lib/fidl/cpp/roundtrip_test.cc
index 3d7c06f..733f2389 100644
--- a/sdk/lib/fidl/cpp/roundtrip_test.cc
+++ b/sdk/lib/fidl/cpp/roundtrip_test.cc
@@ -494,7 +494,7 @@
       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // "after" length
       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // "after" present
 
-      // secondary object 7: "before"
+      // secondary object 7: "after"
       'a',  'f',  't',  'e',  'r',  0x00, 0x00, 0x00,  // "after"
   };
 
@@ -511,6 +511,63 @@
   EXPECT_TRUE(fidl::Equals(input, RoundTrip<XUnionInTable>(input)));
 }
 
+
+TEST(PrimitiveArrayInTable, VerifyWireFormatArrayIsPresent) {
+  PrimitiveArrayInTable input;
+  std::array<int32_t, 9> array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  input.set_before("before");
+  input.set_arr(array);
+  input.set_after("after");
+
+  auto expected = std::vector<uint8_t>{
+      // primary object
+      0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // vector<envelope> element count
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // vector<envelope> present
+
+      // secondary object 1: vector data
+      // vector[0]: envelope<string before>
+      0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // size + handle count
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // "before" is present
+      // vector[1]: envelope<array<int32, 9> arr>
+      0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // size + handle count
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // array is present
+      // vector[2]: envelope<string after>
+      0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // size + handle count
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // "after" is present
+
+      // secondary object 2: "before" length + pointer
+      0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // "before" length
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // "before" present
+
+      // secondary object 3: "before"
+      'b',  'e',  'f',  'o',  'r',  'e',  0x00, 0x00,  // "before"
+
+      // secondary object 4: array content
+      0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+      0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+      0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+      0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+      // secondary object 5: "after" length + pointer
+      0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // "after" length
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // "after" present
+
+      // secondary object 6: "after"
+      'a',  'f',  't',  'e',  'r',  0x00, 0x00, 0x00,  // "after"
+  };
+
+  EXPECT_TRUE(ValueToBytes(input, expected));
+}
+
+TEST(PrimitiveArrayInTable, SerializeAndDeserialize) {
+  PrimitiveArrayInTable input;
+  std::array<int32_t, 9> array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  input.set_arr(array);
+
+  EXPECT_TRUE(fidl::Equals(input, RoundTrip<PrimitiveArrayInTable>(input)));
+}
+
 }  // namespace
 
 }  // namespace misc
diff --git a/zircon/system/ulib/fidl/include/lib/fidl/walker.h b/zircon/system/ulib/fidl/include/lib/fidl/walker.h
index 8b8124a..da2660b 100644
--- a/zircon/system/ulib/fidl/include/lib/fidl/walker.h
+++ b/zircon/system/ulib/fidl/include/lib/fidl/walker.h
@@ -636,10 +636,18 @@
                 continue;
             }
             const fidl_type_t* element_type = frame->array_state.element;
-            Position position = frame->position + element_offset;
-            if (!Push(Frame(element_type, position))) {
-                visitor.OnError("recursion depth exceeded processing array");
-                FIDL_STATUS_GUARD(Status::kConstraintViolationError);
+            if (element_type) {
+                Position position = frame->position + element_offset;
+                if (!Push(Frame(element_type, position))) {
+                    visitor.OnError("recursion depth exceeded processing array");
+                    FIDL_STATUS_GUARD(Status::kConstraintViolationError);
+                }
+            } else {
+                // If there is no element type pointer, the array contents
+                // do not need extra processing, but the array coding table
+                // is present to provide size information when linearizing
+                // envelopes. Just continue.
+                Pop();
             }
             continue;
         }