spirv-fuzz: Do not add constants for Block-decorated structs (#3862)
Fixes #3794.
diff --git a/source/fuzz/transformation_add_constant_composite.cpp b/source/fuzz/transformation_add_constant_composite.cpp
index c036cd5..ac4d599 100644
--- a/source/fuzz/transformation_add_constant_composite.cpp
+++ b/source/fuzz/transformation_add_constant_composite.cpp
@@ -50,7 +50,8 @@
return false;
}
// Gather up the operands for the composite constant, in the process checking
- // whether the given type really defines a composite.
+ // whether the given type really defines a composite and - in the case of a
+ // struct - whether its decorations are OK.
std::vector<uint32_t> constituent_type_ids;
switch (composite_type_instruction->opcode()) {
case SpvOpTypeArray:
@@ -72,6 +73,19 @@
}
break;
case SpvOpTypeStruct:
+ // We do not create constants of structs decorated with Block nor
+ // BufferBlock. The SPIR-V spec does not explicitly disallow this, but it
+ // seems like a strange thing to do, so we disallow it to avoid triggering
+ // low priorty edge case issues related to it.
+ for (auto decoration : {SpvDecorationBlock, SpvDecorationBufferBlock}) {
+ if (!ir_context->get_decoration_mgr()->WhileEachDecoration(
+ composite_type_instruction->result_id(), decoration,
+ [](const opt::Instruction & /*unused*/) -> bool {
+ return false;
+ })) {
+ return false;
+ }
+ }
composite_type_instruction->ForEachInOperand(
[&constituent_type_ids](const uint32_t* member_type_id) {
constituent_type_ids.push_back(*member_type_id);
diff --git a/source/fuzz/transformation_add_constant_composite.h b/source/fuzz/transformation_add_constant_composite.h
index 51345ca..56ac52a 100644
--- a/source/fuzz/transformation_add_constant_composite.h
+++ b/source/fuzz/transformation_add_constant_composite.h
@@ -38,6 +38,8 @@
// - |message_.type_id| must be the id of a composite type
// - |message_.constituent_id| must refer to ids that match the constituent
// types of this composite type
+ // - If |message_.type_id| is a struc type, it must not have the Block or
+ // BufferBlock decoration
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
diff --git a/test/fuzz/transformation_add_constant_composite_test.cpp b/test/fuzz/transformation_add_constant_composite_test.cpp
index 082b673..2b8b838 100644
--- a/test/fuzz/transformation_add_constant_composite_test.cpp
+++ b/test/fuzz/transformation_add_constant_composite_test.cpp
@@ -195,6 +195,92 @@
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
+TEST(TransformationAddConstantCompositeTest, DisallowBufferBlockDecoration) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main"
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 320
+ OpName %4 "main"
+ OpName %7 "buf"
+ OpMemberName %7 0 "a"
+ OpMemberName %7 1 "b"
+ OpName %9 ""
+ OpMemberDecorate %7 0 Offset 0
+ OpMemberDecorate %7 1 Offset 4
+ OpDecorate %7 BufferBlock
+ OpDecorate %9 DescriptorSet 0
+ OpDecorate %9 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %10 = OpConstant %6 42
+ %7 = OpTypeStruct %6 %6
+ %8 = OpTypePointer Uniform %7
+ %9 = OpVariable %8 Uniform
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_0;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ spvtools::ValidatorOptions validator_options;
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+ ASSERT_FALSE(TransformationAddConstantComposite(100, 7, {10, 10}, false)
+ .IsApplicable(context.get(), transformation_context));
+}
+
+TEST(TransformationAddConstantCompositeTest, DisallowBlockDecoration) {
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %4 "main" %9
+ OpExecutionMode %4 LocalSize 1 1 1
+ OpSource ESSL 320
+ OpName %4 "main"
+ OpName %7 "buf"
+ OpMemberName %7 0 "a"
+ OpMemberName %7 1 "b"
+ OpName %9 ""
+ OpMemberDecorate %7 0 Offset 0
+ OpMemberDecorate %7 1 Offset 4
+ OpDecorate %7 Block
+ OpDecorate %9 DescriptorSet 0
+ OpDecorate %9 Binding 0
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %10 = OpConstant %6 42
+ %7 = OpTypeStruct %6 %6
+ %8 = OpTypePointer StorageBuffer %7
+ %9 = OpVariable %8 StorageBuffer
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ spvtools::ValidatorOptions validator_options;
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+ ASSERT_FALSE(TransformationAddConstantComposite(100, 7, {10, 10}, false)
+ .IsApplicable(context.get(), transformation_context));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools