diff --git a/llvm/include/llvm/FuzzMutate/IRMutator.h b/llvm/include/llvm/FuzzMutate/IRMutator.h index 960024652d394..e01b91106fec1 100644 --- a/llvm/include/llvm/FuzzMutate/IRMutator.h +++ b/llvm/include/llvm/FuzzMutate/IRMutator.h @@ -81,6 +81,7 @@ class InjectorIRStrategy : public IRMutationStrategy { RandomIRBuilder &IB); public: + InjectorIRStrategy() : Operations(getDefaultOps()) {} InjectorIRStrategy(std::vector &&Operations) : Operations(std::move(Operations)) {} static std::vector getDefaultOps(); diff --git a/llvm/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp index 2d6c83e49a81c..58d58de9596fb 100644 --- a/llvm/lib/FuzzMutate/IRMutator.cpp +++ b/llvm/lib/FuzzMutate/IRMutator.cpp @@ -45,7 +45,10 @@ void IRMutationStrategy::mutate(Module &M, RandomIRBuilder &IB) { } void IRMutationStrategy::mutate(Function &F, RandomIRBuilder &IB) { - mutate(*makeSampler(IB.Rand, make_pointer_range(F)).getSelection(), IB); + auto Range = make_filter_range(make_pointer_range(F), + [](BasicBlock *BB) { return !BB->isEHPad(); }); + + mutate(*makeSampler(IB.Rand, Range).getSelection(), IB); } void IRMutationStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { @@ -566,7 +569,6 @@ void SinkInstructionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { } void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { - SmallPtrSet AliveInsts; for (auto &I : make_early_inc_range(make_range( BB.getFirstInsertionPt(), BB.getTerminator()->getIterator()))) { diff --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp index 4359ae6c4616b..2ebd0c89e2c0a 100644 --- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp +++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp @@ -262,8 +262,15 @@ static bool isCompatibleReplacement(const Instruction *I, const Use &Operand, case Instruction::Call: case Instruction::Invoke: case Instruction::CallBr: { - const CallBase *II = cast(I); - const Function *Callee = II->getCalledFunction(); + const Function *Callee = cast(I)->getCalledFunction(); + // If it's an indirect call, give up. + if (!Callee) + return false; + // If callee is not an intrinsic, operand 0 is the function to be called. + // Since we cannot assume that the replacement is a function pointer, + // we give up. + if (!Callee->getIntrinsicID() && OperandNo == 0) + return false; return !Callee->hasParamAttribute(OperandNo, Attribute::ImmArg); } default: diff --git a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp index 7afedf756101c..aed95890075e0 100644 --- a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp +++ b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp @@ -533,4 +533,34 @@ TEST(RandomIRBuilderTest, sinkToInstrinsic) { } ASSERT_FALSE(Modified); } + +TEST(RandomIRBuilderTest, DoNotCallPointerWhenSink) { + const char *Source = "\n\ + declare void @g() \n\ + define void @f(ptr %ptr) { \n\ + Entry: \n\ + call void @g() \n\ + ret void \n\ + }"; + LLVMContext Ctx; + std::mt19937 mt(Seed); + std::uniform_int_distribution RandInt(INT_MIN, INT_MAX); + + RandomIRBuilder IB(RandInt(mt), {}); + std::unique_ptr M = parseAssembly(Source, Ctx); + Function &F = *M->getFunction("f"); + BasicBlock &BB = F.getEntryBlock(); + bool Modified = false; + + Instruction *I = &*BB.begin(); + for (int i = 0; i < 20; i++) { + Value *OldOperand = I->getOperand(0); + Value *Src = F.getArg(0); + IB.connectToSink(BB, {I}, Src); + Value *NewOperand = I->getOperand(0); + Modified |= (OldOperand != NewOperand); + ASSERT_FALSE(verifyModule(*M, &errs())); + } + ASSERT_FALSE(Modified); +} } // namespace diff --git a/llvm/unittests/FuzzMutate/StrategiesTest.cpp b/llvm/unittests/FuzzMutate/StrategiesTest.cpp index 1de027c43e49d..850ae16dea442 100644 --- a/llvm/unittests/FuzzMutate/StrategiesTest.cpp +++ b/llvm/unittests/FuzzMutate/StrategiesTest.cpp @@ -665,4 +665,30 @@ TEST(ShuffleBlockStrategy, ShuffleLoop) { }"; VerifyBlockShuffle(Source); } + +TEST(AllStrategies, SkipEHPad) { + StringRef Source = "\n\ + define void @f(i32 %x) personality ptr @__CxxFrameHandler3 { \n\ + entry: \n\ + invoke void @g() to label %try.cont unwind label %catch.dispatch \n\ + catch.dispatch: \n\ + %0 = catchswitch within none [label %catch] unwind to caller \n\ + catch: \n\ + %1 = catchpad within %0 [ptr null, i32 64, ptr null] \n\ + catchret from %1 to label %try.cont \n\ + try.cont: \n\ + ret void \n\ + } \n\ + declare void @g() \n\ + declare i32 @__CxxFrameHandler3(...) \n\ + "; + + mutateAndVerifyModule(Source); + mutateAndVerifyModule(Source); + mutateAndVerifyModule(Source); + mutateAndVerifyModule(Source); + mutateAndVerifyModule(Source); + mutateAndVerifyModule(Source); + mutateAndVerifyModule(Source); +} } // namespace