[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