[tint][wgsl][fuzz] Fix static init ordering bug

Because C++ makes no ordering guarantees, we were having some fuzzers
register themselves before the vector holding the registered fuzzers was
constructed. Upon construction, the vector would wipe away all the
registered fuzzers, and so we were only running those that were
registered after the vector was constructed.

Instead, use a static local to hold the vector. This is guaranteed to be
constructed the first time the function is called, avoiding the ordering
foot-gun.

Change-Id: I1f442e6a15c64f6125bd6866d8f8c00829f2055a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162303
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.cc b/src/tint/cmd/fuzz/wgsl/fuzz.cc
index 7013356..b5a09b0 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.cc
@@ -38,7 +38,14 @@
 namespace tint::fuzz::wgsl {
 namespace {
 
-Vector<ProgramFuzzer, 32> fuzzers;
+/// @returns a reference to the static list of registered ProgramFuzzers.
+/// @note this is not a global, as the static initializers that register fuzzers may be called
+/// before this vector is constructed.
+Vector<ProgramFuzzer, 32>& Fuzzers() {
+    static Vector<ProgramFuzzer, 32> fuzzers;
+    return fuzzers;
+}
+
 thread_local std::string_view currently_running;
 
 [[noreturn]] void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
@@ -50,7 +57,7 @@
 }  // namespace
 
 void Register(const ProgramFuzzer& fuzzer) {
-    fuzzers.Push(fuzzer);
+    Fuzzers().Push(fuzzer);
 }
 
 void Run(std::string_view wgsl, const Options& options) {
@@ -58,7 +65,7 @@
 
     // Ensure that fuzzers are sorted. Without this, the fuzzers may be registered in any order,
     // leading to non-determinism, which we must avoid.
-    TINT_STATIC_INIT(fuzzers.Sort([](auto& a, auto& b) { return a.name < b.name; }));
+    TINT_STATIC_INIT(Fuzzers().Sort([](auto& a, auto& b) { return a.name < b.name; }));
 
     // Create a Source::File to hand to the parser.
     tint::Source::File file("test.wgsl", wgsl);
@@ -71,12 +78,12 @@
 
     // Run each of the program fuzzer functions
     if (options.run_concurrently) {
-        size_t n = fuzzers.Length();
+        size_t n = Fuzzers().Length();
         tint::Vector<std::thread, 32> threads;
         threads.Resize(n);
         for (size_t i = 0; i < n; i++) {
             threads[i] = std::thread([i, &program] {
-                auto& fuzzer = fuzzers[i];
+                auto& fuzzer = Fuzzers()[i];
                 currently_running = fuzzer.name;
                 fuzzer.fn(program);
             });
@@ -86,7 +93,7 @@
         }
     } else {
         TINT_DEFER(currently_running = "");
-        for (auto& fuzzer : fuzzers) {
+        for (auto& fuzzer : Fuzzers()) {
             currently_running = fuzzer.name;
             fuzzer.fn(program);
         }