fuzzer: Implement BuildImpl for msl/hlsl Options structs

The default implementation of this was generating random data for
the underlying pointers of std::unordered_map, leading to crashes
when the map was accessed. This CL populates the map in a
structured manner with pseudo-random data.

Bug: chromium:1273001
Change-Id: Ic20ecab85bedba2a59587ebe4a5016be6e53e6f8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/70701
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/fuzzers/data_builder.h b/fuzzers/data_builder.h
index 39625ef..a931fe0 100644
--- a/fuzzers/data_builder.h
+++ b/fuzzers/data_builder.h
@@ -18,9 +18,12 @@
 #include <cassert>
 #include <functional>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "fuzzers/random_generator.h"
+#include "src/writer/hlsl/generator.h"
+#include "src/writer/msl/generator.h"
 
 namespace tint {
 namespace fuzzers {
@@ -106,6 +109,14 @@
     generator_.GetNBytes(reinterpret_cast<uint8_t*>(out), n);
   }
 
+  /// Generate pseudo-random data of a specific type into an output var
+  /// @tparam T - type of data to produce
+  /// @param out - output var to generate into
+  template <typename T>
+  void build(T& out) {
+    out = build<T>();
+  }
+
   /// Implementation of ::build<T>()
   /// @tparam T - type of data to produce
   template <typename T>
@@ -145,6 +156,70 @@
     /// @returns a boolean with even odds of being true or false
     static bool impl(DataBuilder* b) { return b->generator_.GetBool(); }
   };
+
+  /// Specialization for writer::msl::Options
+  template <>
+  struct BuildImpl<writer::msl::Options> {
+    /// Generate a pseudo-random writer::msl::Options struct
+    /// @param b - data builder to use
+    /// @returns writer::msl::Options filled with pseudo-random data
+    static writer::msl::Options impl(DataBuilder* b) {
+      writer::msl::Options out{};
+      b->build(out.buffer_size_ubo_index);
+      b->build(out.fixed_sample_mask);
+      b->build(out.emit_vertex_point_size);
+      b->build(out.disable_workgroup_init);
+      b->build(out.array_length_from_uniform);
+      return out;
+    }
+  };
+
+  /// Specialization for writer::hlsl::Options
+  template <>
+  struct BuildImpl<writer::hlsl::Options> {
+    /// Generate a pseudo-random writer::hlsl::Options struct
+    /// @param b - data builder to use
+    /// @returns writer::hlsl::Options filled with pseudo-random data
+    static writer::hlsl::Options impl(DataBuilder* b) {
+      writer::hlsl::Options out{};
+      b->build(out.root_constant_binding_point);
+      b->build(out.disable_workgroup_init);
+      b->build(out.array_length_from_uniform);
+      return out;
+    }
+  };
+
+  /// Specialization for writer::ArrayLengthFromUniformOptions
+  template <>
+  struct BuildImpl<writer::ArrayLengthFromUniformOptions> {
+    /// Generate a pseudo-random writer::ArrayLengthFromUniformOptions struct
+    /// @param b - data builder to use
+    /// @returns writer::ArrayLengthFromUniformOptions filled with pseudo-random
+    /// data
+    static writer::ArrayLengthFromUniformOptions impl(DataBuilder* b) {
+      writer::ArrayLengthFromUniformOptions out{};
+      b->build(out.ubo_binding);
+      b->build(out.bindpoint_to_size_index);
+      return out;
+    }
+  };
+
+  /// Specialization for std::unordered_map<K, V>
+  template <typename K, typename V>
+  struct BuildImpl<std::unordered_map<K, V>> {
+    /// Generate a pseudo-random std::unordered_map<K, V>
+    /// @param b - data builder to use
+    /// @returns std::unordered_map<K, V> filled with
+    /// pseudo-random data
+    static std::unordered_map<K, V> impl(DataBuilder* b) {
+      std::unordered_map<K, V> out;
+      uint8_t count = b->build<uint8_t>();
+      for (uint8_t i = 0; i < count; ++i) {
+        out.emplace(b->build<K>(), b->build<V>());
+      }
+      return out;
+    }
+  };
 };
 
 }  // namespace fuzzers
diff --git a/src/writer/array_length_from_uniform_options.h b/src/writer/array_length_from_uniform_options.h
index ae92d4f..2c06287 100644
--- a/src/writer/array_length_from_uniform_options.h
+++ b/src/writer/array_length_from_uniform_options.h
@@ -44,6 +44,9 @@
   /// The mapping from storage buffer binding points to the index into the
   /// uniform buffer where the length of the buffer is stored.
   std::unordered_map<sem::BindingPoint, uint32_t> bindpoint_to_size_index;
+
+  // NOTE: Update fuzzers/data_builder.h when adding or changing any struct
+  // members.
 };
 
 }  // namespace writer
diff --git a/src/writer/hlsl/generator.h b/src/writer/hlsl/generator.h
index 4dacbd4..4013cfa 100644
--- a/src/writer/hlsl/generator.h
+++ b/src/writer/hlsl/generator.h
@@ -56,6 +56,9 @@
   /// Options used to specify a mapping of binding points to indices into a UBO
   /// from which to load buffer sizes.
   ArrayLengthFromUniformOptions array_length_from_uniform = {};
+
+  // NOTE: Update fuzzers/data_builder.h when adding or changing any struct
+  // members.
 };
 
 /// The result produced when generating HLSL.
diff --git a/src/writer/msl/generator.h b/src/writer/msl/generator.h
index 63d7939..7f8f92f 100644
--- a/src/writer/msl/generator.h
+++ b/src/writer/msl/generator.h
@@ -64,6 +64,9 @@
   /// Options used to specify a mapping of binding points to indices into a UBO
   /// from which to load buffer sizes.
   ArrayLengthFromUniformOptions array_length_from_uniform = {};
+
+  // NOTE: Update fuzzers/data_builder.h when adding or changing any struct
+  // members.
 };
 
 /// The result produced when generating MSL.