RandomIRBuilder &IB);
public:
+ InjectorIRStrategy() : Operations(getDefaultOps()) {}
InjectorIRStrategy(std::vector<fuzzerop::OpDescriptor> &&Operations)
: Operations(std::move(Operations)) {}
static std::vector<fuzzerop::OpDescriptor> getDefaultOps();
}
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) {
}
void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
-
SmallPtrSet<Instruction *, 8> AliveInsts;
for (auto &I : make_early_inc_range(make_range(
BB.getFirstInsertionPt(), BB.getTerminator()->getIterator()))) {
case Instruction::Call:
case Instruction::Invoke:
case Instruction::CallBr: {
- const CallBase *II = cast<CallBase>(I);
- const Function *Callee = II->getCalledFunction();
+ const Function *Callee = cast<CallBase>(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:
}
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<int> RandInt(INT_MIN, INT_MAX);
+
+ RandomIRBuilder IB(RandInt(mt), {});
+ std::unique_ptr<Module> 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
}";
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<ShuffleBlockStrategy>(Source);
+ mutateAndVerifyModule<InsertPHIStrategy>(Source);
+ mutateAndVerifyModule<InsertFunctionStrategy>(Source);
+ mutateAndVerifyModule<InsertCFGStrategy>(Source);
+ mutateAndVerifyModule<SinkInstructionStrategy>(Source);
+ mutateAndVerifyModule<InjectorIRStrategy>(Source);
+ mutateAndVerifyModule<InstModificationIRStrategy>(Source);
+}
} // namespace