[tint][ir][fuzz] Check that UserCall Target is valid Fixes: 353960887 Change-Id: I682995c06228ec907a25406962a995bf73ed6efe Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/199134 Auto-Submit: Ryan Harrison <rharrison@chromium.org> Reviewed-by: James Price <jrprice@google.com> Commit-Queue: James Price <jrprice@google.com> Commit-Queue: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc index d9f9da9..f63a499 100644 --- a/src/tint/lang/core/ir/validator.cc +++ b/src/tint/lang/core/ir/validator.cc
@@ -1272,6 +1272,11 @@ return; } + if (!call->Target()) { + AddError(call, UserCall::kFunctionOperandOffset) << "target not defined or not a function"; + return; + } + if (call->Target()->Stage() != Function::PipelineStage::kUndefined) { AddError(call, UserCall::kFunctionOperandOffset) << "call target must not have a pipeline stage";
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc index a065709..b4e6c0b 100644 --- a/src/tint/lang/core/ir/validator_test.cc +++ b/src/tint/lang/core/ir/validator_test.cc
@@ -669,6 +669,39 @@ )"); } +TEST_F(IR_ValidatorTest, CallToNonFunctionTarget) { + auto* g = b.Function("g", ty.void_()); + mod.functions.Pop(); // Remove g, since it isn't actually going to be used, it is just needed + // to create the UserCall before mangling it + + auto* f = b.Function("f", ty.void_()); + b.Append(f->Block(), [&] { + auto* c = b.Call(g); + c->SetOperands(Vector{b.Value(0_i)}); + b.Return(f); + }); + + auto res = ir::Validate(mod); + ASSERT_NE(res, Success); + EXPECT_EQ(res.Failure().reason.Str(), + R"(:3:20 error: call: target not defined or not a function + %2:void = call 0i + ^^ + +:2:3 note: in block + $B1: { + ^^^ + +note: # Disassembly +%f = func():void { + $B1: { + %2:void = call 0i + ret + } +} +)"); +} + TEST_F(IR_ValidatorTest, Construct_Struct_ZeroValue) { auto* str_ty = ty.Struct(mod.symbols.New("MyStruct"), { {mod.symbols.New("a"), ty.i32()},