[llvm] 258cd1f - [FuzzMutate] Handle BB without predecessor, avoid insertion after `musttail call`, avoid sinking token type

Peter Rong via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 1 19:52:23 PDT 2023


Author: Henry Yu
Date: 2023-06-01T19:52:16-07:00
New Revision: 258cd1fc38aa042723b1823ee2bb463928eab35b

URL: https://github.com/llvm/llvm-project/commit/258cd1fc38aa042723b1823ee2bb463928eab35b
DIFF: https://github.com/llvm/llvm-project/commit/258cd1fc38aa042723b1823ee2bb463928eab35b.diff

LOG: [FuzzMutate] Handle BB without predecessor, avoid insertion after `musttail call`, avoid sinking token type

FuzzMutate didn't consider some corner cases and leads to mutation failure when mutating some modules.
This patch fixes 3 bugs:

- Add null check when encountering basic blocks without predecessor to avoid segmentation fault
- Avoid insertion after `musttail call` instruction
- Avoid sinking token type

Unit tests are also added.

Reviewed By: Peter

Differential Revision: https://reviews.llvm.org/D151936

Added: 
    

Modified: 
    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/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp
index df191cad9243b..ea630c4602ba4 100644
--- a/llvm/lib/FuzzMutate/IRMutator.cpp
+++ b/llvm/lib/FuzzMutate/IRMutator.cpp
@@ -114,10 +114,16 @@ InjectorIRStrategy::chooseOperation(Value *Src, RandomIRBuilder &IB) {
   return *RS;
 }
 
+static inline iterator_range<BasicBlock::iterator>
+getInsertionRange(BasicBlock &BB) {
+  auto End = BB.getTerminatingMustTailCall() ? std::prev(BB.end()) : BB.end();
+  return make_range(BB.getFirstInsertionPt(), End);
+}
+
 void InjectorIRStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
   SmallVector<Instruction *, 32> Insts;
-  for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
-    Insts.push_back(&*I);
+  for (Instruction &I : getInsertionRange(BB))
+    Insts.push_back(&I);
   if (Insts.size() < 1)
     return;
 
@@ -360,6 +366,10 @@ void InsertFunctionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
 
   auto RS = makeSampler(IB.Rand, Functions);
   Function *F = RS.getSelection();
+  // Some functions accept metadata type or token type as arguments.
+  // We don't call those functions for now.
+  // For example, `@llvm.dbg.declare(metadata, metadata, metadata)`
+  // https://llvm.org/docs/SourceLevelDebugging.html#llvm-dbg-declare
   auto IsUnsupportedTy = [](Type *T) {
     return T->isMetadataTy() || T->isTokenTy();
   };
@@ -385,7 +395,7 @@ void InsertFunctionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
   };
 
   SmallVector<Instruction *, 32> Insts;
-  for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
+  for (Instruction &I : getInsertionRange(BB))
     Insts.push_back(&I);
   if (Insts.size() < 1)
     return;
@@ -411,7 +421,7 @@ void InsertFunctionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
 
 void InsertCFGStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
   SmallVector<Instruction *, 32> Insts;
-  for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
+  for (Instruction &I : getInsertionRange(BB))
     Insts.push_back(&I);
   if (Insts.size() < 1)
     return;
@@ -551,7 +561,7 @@ void InsertPHIStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
     PHI->addIncoming(Src, Pred);
   }
   SmallVector<Instruction *, 32> InstsAfter;
-  for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
+  for (Instruction &I : getInsertionRange(BB))
     InstsAfter.push_back(&I);
   IB.connectToSink(BB, InstsAfter, PHI);
 }
@@ -563,7 +573,7 @@ void SinkInstructionStrategy::mutate(Function &F, RandomIRBuilder &IB) {
 }
 void SinkInstructionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
   SmallVector<Instruction *, 32> Insts;
-  for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
+  for (Instruction &I : getInsertionRange(BB))
     Insts.push_back(&I);
   if (Insts.size() < 1)
     return;
@@ -572,9 +582,9 @@ void SinkInstructionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
   Instruction *Inst = Insts[Idx];
   // `Idx + 1` so we don't sink to ourselves.
   auto InstsAfter = ArrayRef(Insts).slice(Idx + 1);
-  LLVMContext &C = BB.getParent()->getParent()->getContext();
-  // Don't sink terminators, void function calls, etc.
-  if (Inst->getType() != Type::getVoidTy(C))
+  Type *Ty = Inst->getType();
+  // Don't sink terminators, void function calls, token, etc.
+  if (!Ty->isVoidTy() && !Ty->isTokenTy())
     // Find a new sink and wire up the results of the operation.
     IB.connectToSink(BB, InstsAfter, Inst);
 }

diff  --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
index fff5cfe2ba6ef..bbacfedf456d3 100644
--- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
+++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
@@ -27,7 +27,12 @@ using namespace fuzzerop;
 static std::vector<BasicBlock *> getDominators(BasicBlock *BB) {
   std::vector<BasicBlock *> ret;
   DominatorTree DT(*BB->getParent());
-  DomTreeNode *Node = DT[BB]->getIDom();
+  DomTreeNode *Node = DT.getNode(BB);
+  // It's possible that an orphan block is not in the dom tree. In that case we
+  // just return nothing.
+  if (!Node)
+    return ret;
+  Node = Node->getIDom();
   while (Node && Node->getBlock()) {
     ret.push_back(Node->getBlock());
     // Get parent block.
@@ -41,7 +46,12 @@ static std::vector<BasicBlock *> getDominators(BasicBlock *BB) {
 static std::vector<BasicBlock *> getDominatees(BasicBlock *BB) {
   DominatorTree DT(*BB->getParent());
   std::vector<BasicBlock *> ret;
-  for (DomTreeNode *Child : DT[BB]->children())
+  DomTreeNode *Parent = DT.getNode(BB);
+  // It's possible that an orphan block is not in the dom tree. In that case we
+  // just return nothing.
+  if (!Parent)
+    return ret;
+  for (DomTreeNode *Child : Parent->children())
     ret.push_back(Child->getBlock());
   uint64_t Idx = 0;
   while (Idx < ret.size()) {

diff  --git a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
index aed95890075e0..3ce85f5d7be23 100644
--- a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
+++ b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
@@ -563,4 +563,53 @@ TEST(RandomIRBuilderTest, DoNotCallPointerWhenSink) {
   }
   ASSERT_FALSE(Modified);
 }
+
+TEST(RandomIRBuilderTest, SrcAndSinkWOrphanBlock) {
+  const char *Source = "\n\
+        define i1 @test(i1 %Bool, i32 %Int, i64 %Long) {   \n\
+        Entry:    \n\
+            %Eq0 = icmp eq i64 %Long, 0 \n\
+            br i1 %Eq0, label %True, label %False \n\
+        True: \n\
+            %Or = or i1 %Bool, %Eq0 \n\
+            ret i1 %Or \n\
+        False: \n\
+            %And = and i1 %Bool, %Eq0 \n\
+            ret i1 %And \n\
+        Orphan_1:  \n\
+            %NotBool = sub i1 1, %Bool \n\
+            ret i1 %NotBool \n\
+        Orphan_2:  \n\
+            %Le42 = icmp sle i32 %Int, 42 \n\
+            ret i1 %Le42 \n\
+        }";
+  LLVMContext Ctx;
+  std::mt19937 mt(Seed);
+  std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
+  std::array<Type *, 3> IntTys(
+      {Type::getInt64Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)});
+  std::vector<Value *> Constants;
+  for (Type *IntTy : IntTys) {
+    for (size_t v : {1, 42}) {
+      Constants.push_back(ConstantInt::get(IntTy, v));
+    }
+  }
+  for (int i = 0; i < 10; i++) {
+    RandomIRBuilder IB(RandInt(mt), IntTys);
+    std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
+    Function &F = *M->getFunction("test");
+    for (BasicBlock &BB : F) {
+      SmallVector<Instruction *, 4> Insts;
+      for (Instruction &I : BB) {
+        Insts.push_back(&I);
+      }
+      for (int j = 0; j < 10; j++) {
+        IB.findOrCreateSource(BB, Insts);
+      }
+      for (Value *V : Constants) {
+        IB.connectToSink(BB, Insts, V);
+      }
+    }
+  }
+}
 } // namespace

diff  --git a/llvm/unittests/FuzzMutate/StrategiesTest.cpp b/llvm/unittests/FuzzMutate/StrategiesTest.cpp
index dc2e49831b6d8..d140aa159a3ee 100644
--- a/llvm/unittests/FuzzMutate/StrategiesTest.cpp
+++ b/llvm/unittests/FuzzMutate/StrategiesTest.cpp
@@ -129,6 +129,30 @@ TEST(InjectorIRStrategyTest, LargeInsertion) {
   mutateAndVerifyModule(Source, Mutator, 100);
 }
 
+TEST(InjectorIRStrategyTest, InsertWMustTailCall) {
+  StringRef Source = "\n\
+        define i1 @recursive() {    \n\
+        Entry:     \n\
+            %Ret = musttail call i1 @recursive() \n\
+            ret i1 %Ret \n\
+        }";
+  auto Mutator = createInjectorMutator();
+  ASSERT_TRUE(Mutator);
+  mutateAndVerifyModule(Source, Mutator, 100);
+}
+
+TEST(InjectorIRStrategyTest, InsertWTailCall) {
+  StringRef Source = "\n\
+        define i1 @recursive() {    \n\
+        Entry:     \n\
+            %Ret = tail call i1 @recursive() \n\
+            ret i1 %Ret \n\
+        }";
+  auto Mutator = createInjectorMutator();
+  ASSERT_TRUE(Mutator);
+  mutateAndVerifyModule(Source, Mutator, 100);
+}
+
 TEST(InstDeleterIRStrategyTest, EmptyFunction) {
   // Test that we don't crash even if we can't remove from one of the functions.
 
@@ -576,6 +600,19 @@ TEST(SinkInstructionStrategy, Operand) {
   mutateAndVerifyModule<SinkInstructionStrategy>(Source);
 }
 
+TEST(SinkInstructionStrategy, DoNotSinkTokenType) {
+  StringRef Source = "\n\
+      declare ptr @fake_personality_function() \n\
+      declare token @llvm.experimental.gc.statepoint.p0(i64 immarg %0, i32 immarg %1, ptr %2, i32 immarg %3, i32 immarg %4, ...) \n\
+      define void @test() gc \"statepoint-example\" personality ptr @fake_personality_function { \n\
+      Entry: \n\
+        %token1 = call token (i64, i32, ptr, i32, i32, ...) \
+          @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(ptr addrspace(1) ()) undef, i32 0, i32 0, i32 0, i32 0) \n\
+        ret void \n\
+      }";
+  mutateAndVerifyModule<SinkInstructionStrategy>(Source);
+}
+
 static void VerifyBlockShuffle(StringRef Source) {
   LLVMContext Ctx;
   auto Mutator = createMutator<ShuffleBlockStrategy>();


        


More information about the llvm-commits mailing list