spirv-fuzz: Skip OpFunction when replacing irrelevant ids (#3932)
Fixes #3927.
diff --git a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
index 71f3507..f35ee50 100644
--- a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
+++ b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
@@ -70,10 +70,12 @@
}
// For every type for which we have at least one irrelevant id, record all ids
- // in the module which have that type.
+ // in the module which have that type. Skip ids of OpFunction instructions as
+ // we cannot use these as replacements.
for (const auto& pair : GetIRContext()->get_def_use_mgr()->id_to_defs()) {
uint32_t type_id = pair.second->type_id();
- if (type_id && types_to_ids.count(type_id)) {
+ if (pair.second->opcode() != SpvOpFunction && type_id &&
+ types_to_ids.count(type_id)) {
types_to_ids[type_id].push_back(pair.first);
}
}
@@ -122,7 +124,7 @@
std::vector<uint32_t> available_replacement_ids;
for (auto replacement_id : types_to_ids[type_id]) {
- // We cannot replace an id with itself.
+ // It would be pointless to replace an id with itself.
if (replacement_id == irrelevant_id) {
continue;
}
diff --git a/source/fuzz/transformation_replace_irrelevant_id.cpp b/source/fuzz/transformation_replace_irrelevant_id.cpp
index 7cd4eff..5cea04d 100644
--- a/source/fuzz/transformation_replace_irrelevant_id.cpp
+++ b/source/fuzz/transformation_replace_irrelevant_id.cpp
@@ -64,6 +64,11 @@
return false;
}
+ // The replacement id must not be the result of an OpFunction instruction.
+ if (replacement_id_def->opcode() == SpvOpFunction) {
+ return false;
+ }
+
// Consistency check: an irrelevant id cannot be a pointer.
assert(
!ir_context->get_type_mgr()->GetType(type_id_of_interest)->AsPointer() &&
diff --git a/source/fuzz/transformation_replace_irrelevant_id.h b/source/fuzz/transformation_replace_irrelevant_id.h
index 0210520..35b1987 100644
--- a/source/fuzz/transformation_replace_irrelevant_id.h
+++ b/source/fuzz/transformation_replace_irrelevant_id.h
@@ -32,6 +32,7 @@
// - The id of interest in |message_.id_use_descriptor| is irrelevant
// according to the fact manager.
// - The types of the original id and of the replacement ids are the same.
+ // - The replacement must not be the result id of an OpFunction instruction.
// - |message_.replacement_id| is available to use at the enclosing
// instruction of |message_.id_use_descriptor|.
// - The original id is in principle replaceable with any other id of the same
diff --git a/test/fuzz/transformation_replace_irrelevant_id_test.cpp b/test/fuzz/transformation_replace_irrelevant_id_test.cpp
index 345ef86..828fd82 100644
--- a/test/fuzz/transformation_replace_irrelevant_id_test.cpp
+++ b/test/fuzz/transformation_replace_irrelevant_id_test.cpp
@@ -236,6 +236,55 @@
.IsApplicable(context.get(), transformation_context));
}
+TEST(TransformationReplaceIrrelevantIdTest,
+ DoNotReplaceIrrelevantIdWithOpFunction) {
+ // Checks that an OpFunction result id is not allowed to be used to replace an
+ // irrelevant id.
+ const std::string reference_shader = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %4 "main"
+ OpExecutionMode %4 OriginUpperLeft
+ OpSource ESSL 320
+ %2 = OpTypeVoid
+ %3 = OpTypeFunction %2
+ %6 = OpTypeInt 32 1
+ %7 = OpTypeFunction %6
+ %13 = OpConstant %6 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ %20 = OpCopyObject %6 %13
+ %21 = OpCopyObject %6 %20
+ OpReturn
+ OpFunctionEnd
+ %10 = OpFunction %6 None %7
+ %11 = OpLabel
+ OpReturnValue %13
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
+ const auto consumer = nullptr;
+ const auto context =
+ BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+ spvtools::ValidatorOptions validator_options;
+ ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
+ kConsoleMessageConsumer));
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+ transformation_context.GetFactManager()->AddFactIdIsIrrelevant(20);
+
+ // We cannot replace the use of %20 in by %21 with %10 because %10 is an
+ // OpFunction instruction.
+ ASSERT_FALSE(
+ TransformationReplaceIrrelevantId(
+ MakeIdUseDescriptor(
+ 20, MakeInstructionDescriptor(21, SpvOpCopyObject, 0), 0),
+ 10)
+ .IsApplicable(context.get(), transformation_context));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools