spirv-fuzz: Do not make synonyms of void result ids (#3747)
Fixes #3746.
diff --git a/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp b/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp
index 9262f6f..877a38c 100644
--- a/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp
+++ b/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp
@@ -768,6 +768,13 @@
if (end_type_id_1 == 0 || end_type_id_2 == 0) {
return false;
}
+ // Neither end type is allowed to be void.
+ if (context->get_def_use_mgr()->GetDef(end_type_id_1)->opcode() ==
+ SpvOpTypeVoid ||
+ context->get_def_use_mgr()->GetDef(end_type_id_2)->opcode() ==
+ SpvOpTypeVoid) {
+ return false;
+ }
// If the end types are the same, the data descriptors are comparable.
if (end_type_id_1 == end_type_id_2) {
return true;
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index 768e714..db77f5d 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -271,6 +271,11 @@
return false;
}
auto type_inst = ir_context->get_def_use_mgr()->GetDef(inst->type_id());
+ if (type_inst->opcode() == SpvOpTypeVoid) {
+ // We only make synonyms of instructions that define objects, and an object
+ // cannot have void type.
+ return false;
+ }
if (type_inst->opcode() == SpvOpTypePointer) {
switch (inst->opcode()) {
case SpvOpConstantNull:
diff --git a/test/fuzz/transformation_add_synonym_test.cpp b/test/fuzz/transformation_add_synonym_test.cpp
index 1adc948..93253a1 100644
--- a/test/fuzz/transformation_add_synonym_test.cpp
+++ b/test/fuzz/transformation_add_synonym_test.cpp
@@ -1392,6 +1392,45 @@
.IsApplicable(context.get(), transformation_context));
}
+TEST(TransformationAddSynonym, DoNotCopyVoidRunctionResult) {
+ // This checks that we do not try to copy the result of a void function.
+ std::string shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ OpName %4 "main"
+ OpName %6 "foo("
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %8 = OpFunctionCall %2 %6
+ OpReturn
+ OpFunctionEnd
+ %6 = OpFunction %2 None %3
+ %7 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_3;
+ const auto consumer = nullptr;
+ const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+
+ FactManager fact_manager;
+ spvtools::ValidatorOptions validator_options;
+ TransformationContext transformation_context(&fact_manager,
+ validator_options);
+
+ ASSERT_FALSE(TransformationAddSynonym(
+ 8, protobufs::TransformationAddSynonym::COPY_OBJECT, 500,
+ MakeInstructionDescriptor(8, SpvOpReturn, 0))
+ .IsApplicable(context.get(), transformation_context));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools