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