spirv-reader: reject undef and null pointers
This is defensive. Without variable pointers capabilities, this is
definitely invalid, but not yet checked by the SPIRV-Tools validator.
Bug: tint:807
Change-Id: If9b0b19573b1ca14a1c55aa20c9d42784ec12568
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56700
Auto-Submit: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index fe3d320..e5ca12f 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -4560,6 +4560,8 @@
}
switch (inst.opcode()) {
case SpvOpUndef:
+ return Fail()
+ << "undef pointer is not valid: " << inst.PrettyPrint();
case SpvOpVariable:
// Keep the default decision based on the result type.
break;
diff --git a/src/reader/spirv/function_memory_test.cc b/src/reader/spirv/function_memory_test.cc
index bb16d54..5249114 100644
--- a/src/reader/spirv/function_memory_test.cc
+++ b/src/reader/spirv/function_memory_test.cc
@@ -1280,12 +1280,11 @@
}
TEST_F(SpvParserMemoryTest, DISABLED_RemapStorageBuffer_ThroughFunctionCall) {
- // TODO(dneto): Blocked on OpFunctionCall support.
- // We might need this for passing pointers into atomic builtins.
+ // WGSL does not support pointer-to-storage-buffer as function parameter
}
TEST_F(SpvParserMemoryTest,
DISABLED_RemapStorageBuffer_ThroughFunctionParameter) {
- // TODO(dneto): Blocked on OpFunctionCall support.
+ // WGSL does not support pointer-to-storage-buffer as function parameter
}
std::string RuntimeArrayPreamble() {
@@ -1359,6 +1358,79 @@
)")) << body_str;
}
+std::string InvalidPointerPreamble() {
+ return R"(
+OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+
+%uint = OpTypeInt 32 0
+%ptr_ty = OpTypePointer Function %uint
+
+ %void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+)";
+}
+
+TEST_F(SpvParserMemoryTest, InvalidPointer_Undef_ModuleScope_IsError) {
+ const std::string assembly = InvalidPointerPreamble() + R"(
+ %ptr = OpUndef %ptr_ty
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpCopyObject %ptr_ty %ptr
+ %2 = OpAccessChain %ptr_ty %ptr
+ %3 = OpInBoundsAccessChain %ptr_ty %ptr
+; now show the invalid pointer propagates
+ %10 = OpCopyObject %ptr_ty %1
+ %20 = OpAccessChain %ptr_ty %2
+ %30 = OpInBoundsAccessChain %ptr_ty %3
+ OpReturn
+ OpFunctionEnd
+)";
+ auto p = parser(test::Assemble(assembly));
+ EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+ EXPECT_EQ(p->error(), "undef pointer is not valid: %9 = OpUndef %6");
+}
+
+TEST_F(SpvParserMemoryTest, InvalidPointer_Undef_FunctionScope_IsError) {
+ const std::string assembly = InvalidPointerPreamble() + R"(
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %ptr = OpUndef %ptr_ty
+ OpReturn
+ OpFunctionEnd
+)";
+ auto p = parser(test::Assemble(assembly));
+ EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+ EXPECT_EQ(p->error(), "undef pointer is not valid: %7 = OpUndef %3");
+}
+
+TEST_F(SpvParserMemoryTest, InvalidPointer_ConstantNull_IsError) {
+ // OpConstantNull on logical pointer requires variable-pointers, which
+ // is not (yet) supported by WGSL features.
+ const std::string assembly = InvalidPointerPreamble() + R"(
+ %ptr = OpConstantNull %ptr_ty
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpCopyObject %ptr_ty %ptr
+ %2 = OpAccessChain %ptr_ty %ptr
+ %3 = OpInBoundsAccessChain %ptr_ty %ptr
+; now show the invalid pointer propagates
+ %10 = OpCopyObject %ptr_ty %1
+ %20 = OpAccessChain %ptr_ty %2
+ %30 = OpInBoundsAccessChain %ptr_ty %3
+ OpReturn
+ OpFunctionEnd
+)";
+ auto p = parser(test::Assemble(assembly));
+ EXPECT_FALSE(p->BuildAndParseInternalModule());
+ EXPECT_EQ(p->error(), "null pointer is not valid: %9 = OpConstantNull %6");
+}
+
} // namespace
} // namespace spirv
} // namespace reader
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 25a67bf..32d3f9f 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -610,6 +610,9 @@
if (!RegisterTypes()) {
return false;
}
+ if (!RejectInvalidPointerRoots()) {
+ return false;
+ }
if (!EmitScalarSpecConstants()) {
return false;
}
@@ -1288,6 +1291,33 @@
return success_;
}
+bool ParserImpl::RejectInvalidPointerRoots() {
+ if (!success_) {
+ return false;
+ }
+ for (auto& inst : module_->types_values()) {
+ if (const auto* result_type = type_mgr_->GetType(inst.type_id())) {
+ if (result_type->AsPointer()) {
+ switch (inst.opcode()) {
+ case SpvOpVariable:
+ // This is the only valid case.
+ break;
+ case SpvOpUndef:
+ return Fail() << "undef pointer is not valid: "
+ << inst.PrettyPrint();
+ case SpvOpConstantNull:
+ return Fail() << "null pointer is not valid: "
+ << inst.PrettyPrint();
+ default:
+ return Fail() << "module-scope pointer is not valid: "
+ << inst.PrettyPrint();
+ }
+ }
+ }
+ }
+ return success();
+}
+
bool ParserImpl::EmitScalarSpecConstants() {
if (!success_) {
return false;
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index b93a993..99b7cf7 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -349,6 +349,11 @@
/// @returns true if parser is still successful.
bool RegisterTypes();
+ /// Fail if there are any module-scope pointer values other than those
+ /// declared by OpVariable.
+ /// @returns true if parser is still successful.
+ bool RejectInvalidPointerRoots();
+
/// Register sampler and texture usage for memory object declarations.
/// This must be called after we've registered line numbers for all
/// instructions. This is a no-op if the parser has already failed.
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index 54c8468..0ca4db3 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -344,7 +344,7 @@
const std::string assembly = PerVertexPreamble() + R"(
%main = OpFunction %void None %voidfn
%entry = OpLabel
- %1000 = OpUndef %11
+ %1000 = OpCopyObject %11 %1
OpReturn
OpFunctionEnd
)";
@@ -352,7 +352,7 @@
EXPECT_FALSE(p->BuildAndParseInternalModule());
EXPECT_THAT(p->error(),
Eq("operations producing a pointer to a per-vertex structure are "
- "not supported: %1000 = OpUndef %11"))
+ "not supported: %1000 = OpCopyObject %11 %1"))
<< p->error();
}