diff --git a/source/fuzz/fuzzer_pass_add_synonyms.cpp b/source/fuzz/fuzzer_pass_add_synonyms.cpp index f1091740b..2fa070004 100644 --- a/source/fuzz/fuzzer_pass_add_synonyms.cpp +++ b/source/fuzz/fuzzer_pass_add_synonyms.cpp @@ -36,6 +36,12 @@ void FuzzerPassAddSynonyms::Apply() { [this](opt::Function* function, opt::BasicBlock* block, opt::BasicBlock::iterator inst_it, const protobufs::InstructionDescriptor& instruction_descriptor) { + if (GetTransformationContext()->GetFactManager()->BlockIsDead( + block->id())) { + // Don't create synonyms in dead blocks. + return; + } + // Skip |inst_it| if we can't insert anything above it. OpIAdd is just // a representative of some instruction that might be produced by the // transformation. diff --git a/source/fuzz/fuzzer_pass_copy_objects.cpp b/source/fuzz/fuzzer_pass_copy_objects.cpp index 4cc4044fe..9f7bbd63f 100644 --- a/source/fuzz/fuzzer_pass_copy_objects.cpp +++ b/source/fuzz/fuzzer_pass_copy_objects.cpp @@ -41,6 +41,12 @@ void FuzzerPassCopyObjects::Apply() { "The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction"); + if (GetTransformationContext()->GetFactManager()->BlockIsDead( + block->id())) { + // Don't create synonyms in dead blocks. + return; + } + // Check whether it is legitimate to insert a copy before this // instruction. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject, diff --git a/source/fuzz/transformation_add_synonym.cpp b/source/fuzz/transformation_add_synonym.cpp index fb657d7db..bd9df132e 100644 --- a/source/fuzz/transformation_add_synonym.cpp +++ b/source/fuzz/transformation_add_synonym.cpp @@ -68,6 +68,17 @@ bool TransformationAddSynonym::IsApplicable( return false; } + const auto* insert_before_inst_block = + ir_context->get_instr_block(insert_before_inst); + assert(insert_before_inst_block && + "|insert_before_inst| must be in some block"); + + if (transformation_context.GetFactManager()->BlockIsDead( + insert_before_inst_block->id())) { + // We don't create synonyms in dead blocks. + return false; + } + // Check that we can insert |message._synonymous_instruction| before // |message_.insert_before| instruction. We use OpIAdd to represent some // instruction that can produce a synonym. diff --git a/test/fuzz/transformation_add_synonym_test.cpp b/test/fuzz/transformation_add_synonym_test.cpp index aef088d33..603a3dbf7 100644 --- a/test/fuzz/transformation_add_synonym_test.cpp +++ b/test/fuzz/transformation_add_synonym_test.cpp @@ -1334,7 +1334,7 @@ TEST(TransformationAddSynonymTest, PropagateIrrelevantPointeeFact) { transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101)); } -TEST(TransformationAddSynonym, DoNotCopyOpSampledImage) { +TEST(TransformationAddSynonymTest, DoNotCopyOpSampledImage) { // This checks that we do not try to copy the result id of an OpSampledImage // instruction. std::string shader = R"( @@ -1392,7 +1392,7 @@ TEST(TransformationAddSynonym, DoNotCopyOpSampledImage) { .IsApplicable(context.get(), transformation_context)); } -TEST(TransformationAddSynonym, DoNotCopyVoidRunctionResult) { +TEST(TransformationAddSynonymTest, DoNotCopyVoidRunctionResult) { // This checks that we do not try to copy the result of a void function. std::string shader = R"( OpCapability Shader @@ -1431,6 +1431,57 @@ TEST(TransformationAddSynonym, DoNotCopyVoidRunctionResult) { .IsApplicable(context.get(), transformation_context)); } +TEST(TransformationAddSynonymTest, HandlesDeadBlocks) { + std::string 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 = OpTypeBool + %7 = OpConstantTrue %6 + %11 = OpTypePointer Function %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + OpSelectionMerge %10 None + OpBranchConditional %7 %8 %9 + %8 = OpLabel + OpBranch %10 + %9 = OpLabel + OpBranch %10 + %10 = 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(context.get()); + spvtools::ValidatorOptions validator_options; + TransformationContext transformation_context(&fact_manager, + validator_options); + + fact_manager.AddFactBlockIsDead(9); + + auto insert_before = MakeInstructionDescriptor(9, SpvOpBranch, 0); + + ASSERT_FALSE(TransformationAddSynonym( + 7, protobufs::TransformationAddSynonym::COPY_OBJECT, 100, + insert_before) + .IsApplicable(context.get(), transformation_context)); + + ASSERT_FALSE(TransformationAddSynonym( + 12, protobufs::TransformationAddSynonym::COPY_OBJECT, 100, + insert_before) + .IsApplicable(context.get(), transformation_context)); +} + } // namespace } // namespace fuzz } // namespace spvtools