Guard against overflow in substitute overrides.

Check that the array size does not overflow when doing override
substitution.

Bug: 483751167
Change-Id: I2b1a1a4906e935e689230d4fcf6ad8a65ac5bf1d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/290475
Reviewed-by: David Neto <dneto@google.com>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
(cherry picked from commit 3bb27093dc97491901bc61eb3ba289cd4341fdad)
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/292055
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/transform/substitute_overrides.cc b/src/tint/lang/core/ir/transform/substitute_overrides.cc
index a6464bb..4e1ebf7 100644
--- a/src/tint/lang/core/ir/transform/substitute_overrides.cc
+++ b/src/tint/lang/core/ir/transform/substitute_overrides.cc
@@ -29,6 +29,7 @@
 
 #include <cstdint>
 #include <functional>
+#include <limits>
 #include <utility>
 
 #include "src/tint/lang/core/binary_op.h"
@@ -211,9 +212,18 @@
             }
 
             uint32_t num_elements = new_value->Value()->ValueAs<uint32_t>();
+            uint64_t new_ary_size = uint64_t{num_elements} * old_ty->ImplicitStride();
+            if (new_ary_size > std::numeric_limits<uint32_t>::max()) {
+                diag::Diagnostic error{};
+                error.severity = diag::Severity::Error;
+                error.source = ir.SourceOf(cnt->value);
+                error << "array size (" << new_ary_size << ") is too large";
+                return diag::Failure(error);
+            }
+
             auto* new_cnt = ty.Get<core::type::ConstantArrayCount>(num_elements);
             auto* new_ty = ty.Get<core::type::Array>(old_ty->ElemType(), new_cnt,
-                                                     num_elements * old_ty->ImplicitStride());
+                                                     static_cast<uint32_t>(new_ary_size));
 
             auto* new_ptr = ty.ptr(old_ptr->AddressSpace(), new_ty, old_ptr->Access());
             var->Result()->SetType(new_ptr);
diff --git a/src/tint/lang/core/ir/transform/substitute_overrides_test.cc b/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
index 35d9b6b..ae92c66 100644
--- a/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
+++ b/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
@@ -1909,5 +1909,50 @@
     EXPECT_EQ(result.Failure().reason, R"(5:8 error: array count (-1) must be greater than 0)");
 }
 
+// See https://crbug.com/483751167
+TEST_F(IR_SubstituteOverridesTest, OverrideArraySizeOverflow) {
+    ir::Var* v = nullptr;
+    b.Append(mod.root_block, [&] {
+        auto* x = b.Override("x", ty.i32());
+        x->SetOverrideId({0});
+
+        auto* cnt = ty.Get<core::ir::type::ValueArrayCount>(x->Result());
+        mod.SetSource(cnt->value, Source{{5, 8}});
+        auto* ary = ty.Get<core::type::Array>(ty.u32(), cnt, 4_u);
+        v = b.Var("v", ty.ptr(core::AddressSpace::kWorkgroup, ary, core::Access::kReadWrite));
+        mod.SetSource(v, Source{{3, 2}});
+    });
+
+    auto* func = b.Function("foo", ty.u32());
+    b.Append(func->Block(), [&] {
+        auto* access = b.Access(ty.ptr<workgroup, u32>(), v, 10000_u);
+        auto* load = b.Load(access);
+        b.Return(func, load);
+    });
+
+    auto* src = R"(
+$B1: {  # root
+  %x:i32 = override undef @id(0)
+  %v:ptr<workgroup, array<u32, %x>, read_write> = var undef
+}
+
+%foo = func():u32 {
+  $B2: {
+    %4:ptr<workgroup, u32, read_write> = access %v, 10000u
+    %5:u32 = load %4
+    ret %5
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    SubstituteOverridesConfig cfg{};
+    cfg.map[OverrideId{0}] = 1'073'741'825;
+    auto result = RunWithFailure(SubstituteOverrides, cfg);
+    ASSERT_NE(result, Success);
+    EXPECT_EQ(result.Failure().reason, R"(5:8 error: array size (4294967300) is too large)");
+}
+
 }  // namespace
 }  // namespace tint::core::ir::transform