[llvm] 66892f2 - [FuzzMutate] Skip EHPad during mutation and avoid replacing callee with pointer when sinking
Peter Rong via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 26 16:45:56 PDT 2023
Author: Henry Yu
Date: 2023-04-26T16:45:49-07:00
New Revision: 66892f25af005e42adf55f9615d4919b0cd3ac7d
URL: https://github.com/llvm/llvm-project/commit/66892f25af005e42adf55f9615d4919b0cd3ac7d
DIFF: https://github.com/llvm/llvm-project/commit/66892f25af005e42adf55f9615d4919b0cd3ac7d.diff
LOG: [FuzzMutate] Skip EHPad during mutation and avoid replacing callee with pointer when sinking
This patch addresses 2 problems:
- In `ShuffleBlockStrategy`, when `BB` is an EHPad, `BB.getFirstInsertionPt()` will return `BB.end()`, which cannot be dereferenced and will cause crash in following loop.
- In `isCompatibleReplacement`, a call instruction's callee might be replaced by a pointer, causing 2 subproblems:
- we cannot guarantee that the pointer is a function pointer (even if it is, we cannot guarantee it matches the signature).
- after such a replacement, `getCalledFunction` will from then on return `nullptr` (since it's indirect call) which causes Segmentation Fault in the lines below.
This patch fixes the first problem by checking if a block to be mutated is an EHPad in base class `IRMutationStrategy` and skipping mutating it if so.
This patch fixes the second problem by avoiding replacing callee with pointer and adding a null check for indirect calls.
Reviewed By: Peter
Differential Revision: https://reviews.llvm.org/D148853
Added:
Modified:
llvm/include/llvm/FuzzMutate/IRMutator.h
llvm/lib/FuzzMutate/IRMutator.cpp
llvm/lib/FuzzMutate/RandomIRBuilder.cpp
llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
llvm/unittests/FuzzMutate/StrategiesTest.cpp
Removed:
################################################################################
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<fuzzerop::OpDescriptor> &&Operations)
: Operations(std::move(Operations)) {}
static std::vector<fuzzerop::OpDescriptor> 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<Instruction *, 8> 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<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:
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<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
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<ShuffleBlockStrategy>(Source);
+ mutateAndVerifyModule<InsertPHIStrategy>(Source);
+ mutateAndVerifyModule<InsertFunctionStrategy>(Source);
+ mutateAndVerifyModule<InsertCFGStrategy>(Source);
+ mutateAndVerifyModule<SinkInstructionStrategy>(Source);
+ mutateAndVerifyModule<InjectorIRStrategy>(Source);
+ mutateAndVerifyModule<InstModificationIRStrategy>(Source);
+}
} // namespace
More information about the llvm-commits
mailing list