spirv-fuzz: Fixes related to irrelevant ids (#3901)
Fixes #3899.
Fixes #3900.
diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
index 9cbf590..ae9a754 100644
--- a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
@@ -147,6 +147,15 @@
: parent_block->terminator();
}
+ if (GetTransformationContext()->GetFactManager()->BlockIsDead(
+ GetIRContext()
+ ->get_instr_block(instruction_to_insert_before)
+ ->id())) {
+ // We cannot create a synonym via a composite extraction in a dead
+ // block, as the resulting id is irrelevant.
+ continue;
+ }
+
assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
synonym_to_try->object()) &&
"Irrelevant ids can't participate in DataSynonym facts");
@@ -155,6 +164,11 @@
instruction_to_insert_before),
id_with_which_to_replace_use, synonym_to_try->object(),
fuzzerutil::RepeatedFieldToVector(synonym_to_try->index())));
+ assert(GetTransformationContext()->GetFactManager()->IsSynonymous(
+ MakeDataDescriptor(id_with_which_to_replace_use, {}),
+ *synonym_to_try) &&
+ "The extracted id must be synonymous with the component from "
+ "which it was extracted.");
}
ApplyTransformation(TransformationReplaceIdWithSynonym(
diff --git a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
index 0be00c7..71f3507 100644
--- a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
+++ b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
@@ -127,6 +127,14 @@
continue;
}
+ // We cannot replace a variable initializer with a non-constant.
+ if (TransformationReplaceIrrelevantId::
+ AttemptsToReplaceVariableInitializerWithNonConstant(
+ *use_inst, *GetIRContext()->get_def_use_mgr()->GetDef(
+ replacement_id))) {
+ continue;
+ }
+
// Only consider this replacement if the use point is within a basic
// block and the id is available at the use point.
//
diff --git a/source/fuzz/transformation_replace_irrelevant_id.cpp b/source/fuzz/transformation_replace_irrelevant_id.cpp
index 9866c08..7cd4eff 100644
--- a/source/fuzz/transformation_replace_irrelevant_id.cpp
+++ b/source/fuzz/transformation_replace_irrelevant_id.cpp
@@ -69,10 +69,17 @@
!ir_context->get_type_mgr()->GetType(type_id_of_interest)->AsPointer() &&
"An irrelevant id cannot be a pointer");
+ uint32_t use_in_operand_index =
+ message_.id_use_descriptor().in_operand_index();
+
// The id use must be replaceable with any other id of the same type.
- if (!fuzzerutil::IdUseCanBeReplaced(
- ir_context, use_instruction,
- message_.id_use_descriptor().in_operand_index())) {
+ if (!fuzzerutil::IdUseCanBeReplaced(ir_context, use_instruction,
+ use_in_operand_index)) {
+ return false;
+ }
+
+ if (AttemptsToReplaceVariableInitializerWithNonConstant(
+ *use_instruction, *replacement_id_def)) {
return false;
}
@@ -111,5 +118,13 @@
return std::unordered_set<uint32_t>();
}
+bool TransformationReplaceIrrelevantId::
+ AttemptsToReplaceVariableInitializerWithNonConstant(
+ const opt::Instruction& use_instruction,
+ const opt::Instruction& replacement_for_use) {
+ return use_instruction.opcode() == SpvOpVariable &&
+ !spvOpcodeIsConstant(replacement_for_use.opcode());
+}
+
} // namespace fuzz
} // namespace spvtools
diff --git a/source/fuzz/transformation_replace_irrelevant_id.h b/source/fuzz/transformation_replace_irrelevant_id.h
index 81bde34..0210520 100644
--- a/source/fuzz/transformation_replace_irrelevant_id.h
+++ b/source/fuzz/transformation_replace_irrelevant_id.h
@@ -50,6 +50,13 @@
protobufs::Transformation ToMessage() const override;
+ // Returns true if and only if |use_instruction| is OpVariable and
+ // |replacement_for_use| is not a constant instruction - i.e., if it would be
+ // illegal to replace the variable's initializer with the given instruction.
+ static bool AttemptsToReplaceVariableInitializerWithNonConstant(
+ const opt::Instruction& use_instruction,
+ const opt::Instruction& replacement_for_use);
+
private:
protobufs::TransformationReplaceIrrelevantId message_;
};
diff --git a/test/fuzz/transformation_replace_irrelevant_id_test.cpp b/test/fuzz/transformation_replace_irrelevant_id_test.cpp
index cc6cc51..d38e726 100644
--- a/test/fuzz/transformation_replace_irrelevant_id_test.cpp
+++ b/test/fuzz/transformation_replace_irrelevant_id_test.cpp
@@ -184,6 +184,55 @@
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
+TEST(TransformationReplaceIrrelevantIdTest,
+ DoNotReplaceVariableInitializerWithNonConstant) {
+ // Checks that it is not possible to replace the initializer of a variable
+ // with a non-constant id (such as a function parameter).
+ 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 = OpTypePointer Function %6
+ %8 = OpTypeFunction %2 %6
+ %13 = OpConstant %6 2
+ %4 = OpFunction %2 None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %10 = OpFunction %2 None %8
+ %9 = OpFunctionParameter %6
+ %11 = OpLabel
+ %12 = OpVariable %7 Function %13
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ const auto env = SPV_ENV_UNIVERSAL_1_5;
+ const auto consumer = nullptr;
+ const auto context =
+ BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
+ ASSERT_TRUE(IsValid(env, context.get()));
+
+ spvtools::ValidatorOptions validator_options;
+ TransformationContext transformation_context(
+ MakeUnique<FactManager>(context.get()), validator_options);
+ transformation_context.GetFactManager()->AddFactIdIsIrrelevant(13);
+
+ // We cannot replace the use of %13 in the initializer of %12 with %9 because
+ // %9 is not a constant.
+ ASSERT_FALSE(TransformationReplaceIrrelevantId(
+ MakeIdUseDescriptor(
+ 13, MakeInstructionDescriptor(12, SpvOpVariable, 0), 1),
+ 9)
+ .IsApplicable(context.get(), transformation_context));
+}
+
} // namespace
} // namespace fuzz
} // namespace spvtools