[tint][ir][fuzz] Prevent fuzzer from crashing on malformed loads

Fixes: 352528962
Change-Id: I1c150a3cc12a6f3a61ccc69712ad96f1606729a7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/198115
Reviewed-by: James Price <jrprice@google.com>
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/tint/lang/core/ir/load.h b/src/tint/lang/core/ir/load.h
index 5a2af5d..7c51aa8 100644
--- a/src/tint/lang/core/ir/load.h
+++ b/src/tint/lang/core/ir/load.h
@@ -41,6 +41,12 @@
     /// The offset in Operands() for the from value
     static constexpr size_t kFromOperandOffset = 0;
 
+    /// The fixed number of results returned by this instruction
+    static constexpr size_t kNumResults = 1;
+
+    /// The fixed number of operands used by this instruction
+    static constexpr size_t kNumOperands = 1;
+
     /// Constructor (no results, no operands)
     Load();
 
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 2b90745..d3b7ad0 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -1670,7 +1670,9 @@
 }
 
 void Validator::CheckLoad(const Load* l) {
-    CheckOperandNotNull(l, l->From(), Load::kFromOperandOffset);
+    if (TINT_UNLIKELY(!CheckResultsAndOperands(l, Load::kNumResults, Load::kNumOperands))) {
+        return;
+    }
 
     if (auto* from = l->From()) {
         auto* mv = from->Type()->As<core::type::MemoryView>();
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 9c5e4c8..dc96213 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -4677,6 +4677,39 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, Load_MissingResult) {
+    auto* f = b.Function("my_func", ty.void_());
+
+    b.Append(f->Block(), [&] {
+        auto* var = b.Var(ty.ptr<function, i32>());
+        auto* load = mod.allocators.instructions.Create<ir::Load>(nullptr, var->Result(0));
+        load->ClearResults();
+        b.Append(load);
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:4:13 error: load: expected exactly 1 results, got 0
+    undef = load %2
+            ^^^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%my_func = func():void {
+  $B1: {
+    %2:ptr<function, i32, read_write> = var
+    undef = load %2
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, Store_NullTo) {
     auto* f = b.Function("my_func", ty.void_());