[tint][ir][fuzz] Handle malformed StoreVectorElement in validator
- Removes unused `CheckOperandsNotNull`
Issue: 345196551
Fixes: 355451180
Change-Id: I37ea66c826c66bf3a0e5174b2413d0a0ead651e9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200061
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/tint/lang/core/ir/store_vector_element.h b/src/tint/lang/core/ir/store_vector_element.h
index 9230bf0..22c29ed 100644
--- a/src/tint/lang/core/ir/store_vector_element.h
+++ b/src/tint/lang/core/ir/store_vector_element.h
@@ -47,6 +47,12 @@
/// The offset in Operands() for the `value` value
static constexpr size_t kValueOperandOffset = 2;
+ /// The fixed number of results returned by this instruction
+ static constexpr size_t kNumResults = 0;
+
+ /// The fixed number of operands used by this instruction
+ static constexpr size_t kNumOperands = 3;
+
/// Constructor (no operands)
StoreVectorElement();
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index a932edc..0406d33 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -364,15 +364,6 @@
// TODO(345196551): Remove this override once it is no longer used.
void CheckOperandNotNull(const ir::Instruction* inst, const ir::Value* operand, size_t idx);
- /// Checks all operands in the given range (inclusive) for @p inst are not null
- /// @param inst the instruction
- /// @param start_operand the first operand to check
- /// @param end_operand the last operand to check
- // TODO(345196551): Remove this override once it is no longer used.
- void CheckOperandsNotNull(const ir::Instruction* inst,
- size_t start_operand,
- size_t end_operand);
-
/// Validates the root block
/// @param blk the block
void CheckRootBlock(const Block* blk);
@@ -911,16 +902,6 @@
}
}
-// TODO(353498500): Remove this function once it is no longer used.
-void Validator::CheckOperandsNotNull(const Instruction* inst,
- size_t start_operand,
- size_t end_operand) {
- auto operands = inst->Operands();
- for (size_t i = start_operand; i <= end_operand; i++) {
- CheckOperandNotNull(inst, operands[i], i);
- }
-}
-
void Validator::CheckRootBlock(const Block* blk) {
block_stack_.Push(blk);
TINT_DEFER(block_stack_.Pop());
@@ -1871,9 +1852,10 @@
}
void Validator::CheckStoreVectorElement(const StoreVectorElement* s) {
- CheckOperandsNotNull(s, //
- StoreVectorElement::kToOperandOffset,
- StoreVectorElement::kValueOperandOffset);
+ if (!CheckResultsAndOperands(s, StoreVectorElement::kNumResults,
+ StoreVectorElement::kNumOperands)) {
+ return;
+ }
if (auto* value = s->Value()) {
if (auto* el_ty = GetVectorPtrElementType(s, StoreVectorElement::kToOperandOffset)) {
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 538738d..1ba3dcc 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -5958,14 +5958,14 @@
b.Append(f->Block(), [&] {
b.Append(mod.allocators.instructions.Create<ir::StoreVectorElement>(
- nullptr, b.Constant(1_i), b.Constant(2_i)));
+ nullptr, b.Constant(1_i), b.Constant(2_f)));
b.Return(f);
});
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(), R"(:3:26 error: store_vector_element: operand is undefined
- store_vector_element undef, 1i, 2i
+ store_vector_element undef, 1i, 2.0f
^^^^^
:2:3 note: in block
@@ -5975,7 +5975,7 @@
note: # Disassembly
%my_func = func():void {
$B1: {
- store_vector_element undef, 1i, 2i
+ store_vector_element undef, 1i, 2.0f
ret
}
}
@@ -5988,33 +5988,25 @@
b.Append(f->Block(), [&] {
auto* var = b.Var(ty.ptr<function, vec3<f32>>());
b.Append(mod.allocators.instructions.Create<ir::StoreVectorElement>(var->Result(0), nullptr,
- b.Constant(2_i)));
+ b.Constant(2_f)));
b.Return(f);
});
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(), R"(:4:30 error: store_vector_element: operand is undefined
- store_vector_element %2, undef, 2i
+ store_vector_element %2, undef, 2.0f
^^^^^
:2:3 note: in block
$B1: {
^^^
-:4:37 error: store_vector_element: value type 'i32' does not match vector pointer element type 'f32'
- store_vector_element %2, undef, 2i
- ^^
-
-:2:3 note: in block
- $B1: {
- ^^^
-
note: # Disassembly
%my_func = func():void {
$B1: {
%2:ptr<function, vec3<f32>, read_write> = var
- store_vector_element %2, undef, 2i
+ store_vector_element %2, undef, 2.0f
ret
}
}
@@ -6052,6 +6044,70 @@
)");
}
+TEST_F(IR_ValidatorTest, StoreVectorElement_MissingOperands) {
+ auto* f = b.Function("my_func", ty.void_());
+
+ b.Append(f->Block(), [&] {
+ auto* var = b.Var(ty.ptr<function, vec3<f32>>());
+ auto* store = b.StoreVectorElement(var, b.Constant(1_i), b.Constant(2_f));
+ store->ClearOperands();
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:4:5 error: store_vector_element: expected exactly 3 operands, got 0
+ store_vector_element
+ ^^^^^^^^^^^^^^^^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%my_func = func():void {
+ $B1: {
+ %2:ptr<function, vec3<f32>, read_write> = var
+ store_vector_element
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, StoreVectorElement_UnexpectedResult) {
+ auto* f = b.Function("my_func", ty.void_());
+
+ b.Append(f->Block(), [&] {
+ auto* var = b.Var(ty.ptr<function, vec3<f32>>());
+ auto* store = b.StoreVectorElement(var, b.Constant(1_i), b.Constant(2_f));
+ store->SetResults(Vector{b.InstructionResult(ty.f32())});
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:4:5 error: store_vector_element: expected exactly 0 results, got 1
+ store_vector_element %2, 1i, 2.0f
+ ^^^^^^^^^^^^^^^^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%my_func = func():void {
+ $B1: {
+ %2:ptr<function, vec3<f32>, read_write> = var
+ store_vector_element %2, 1i, 2.0f
+ ret
+ }
+}
+)");
+}
+
TEST_F(IR_ValidatorTest, Scoping_UseBeforeDecl) {
auto* f = b.Function("my_func", ty.void_());