[llvm] 6998b34 - [FuzzMutate] InsertFunctionStrategy
Peter Rong via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 19 20:09:18 PDT 2023
Author: Peter Rong
Date: 2023-04-19T20:09:12-07:00
New Revision: 6998b34c7ac889a586d22b4aa69580899b716452
URL: https://github.com/llvm/llvm-project/commit/6998b34c7ac889a586d22b4aa69580899b716452
DIFF: https://github.com/llvm/llvm-project/commit/6998b34c7ac889a586d22b4aa69580899b716452.diff
LOG: [FuzzMutate] InsertFunctionStrategy
InsertFunctionStrategy does two things:
1. Add a random function declaration or definition to the module. This would replace previously used `createEmptyFunction`.
2. Add a random function call between instructions.
Reviewed By: arsenm
Differential Revision: https://reviews.llvm.org/D148568
Added:
Modified:
llvm/include/llvm/FuzzMutate/IRMutator.h
llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
llvm/lib/FuzzMutate/IRMutator.cpp
llvm/lib/FuzzMutate/RandomIRBuilder.cpp
llvm/unittests/FuzzMutate/StrategiesTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/FuzzMutate/IRMutator.h b/llvm/include/llvm/FuzzMutate/IRMutator.h
index 38f8f7ba16237..960024652d394 100644
--- a/llvm/include/llvm/FuzzMutate/IRMutator.h
+++ b/llvm/include/llvm/FuzzMutate/IRMutator.h
@@ -118,6 +118,20 @@ class InstModificationIRStrategy : public IRMutationStrategy {
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
};
+/// Strategy that generates new function calls and inserts function signatures
+/// to the modules. If any signatures are present in the module it will be
+/// called.
+class InsertFunctionStrategy : public IRMutationStrategy {
+public:
+ uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
+ uint64_t CurrentWeight) override {
+ return 10;
+ }
+
+ using IRMutationStrategy::mutate;
+ void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
+};
+
/// Strategy to split a random block and insert a random CFG in between.
class InsertCFGStrategy : public IRMutationStrategy {
private:
diff --git a/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h b/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
index de66c080809d8..3985c56cb3176 100644
--- a/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
+++ b/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
@@ -24,9 +24,9 @@ class Function;
class GlobalVariable;
class Instruction;
class LLVMContext;
+class Module;
class Type;
class Value;
-class Module;
namespace fuzzerop {
class SourcePred;
@@ -38,6 +38,10 @@ struct RandomIRBuilder {
RandomEngine Rand;
SmallVector<Type *, 16> KnownTypes;
+ uint64_t MinArgNum = 0;
+ uint64_t MaxArgNum = 5;
+ uint64_t MinFunctionNum = 1;
+
RandomIRBuilder(int Seed, ArrayRef<Type *> AllowedTypes)
: Rand(Seed), KnownTypes(AllowedTypes.begin(), AllowedTypes.end()) {}
@@ -98,6 +102,10 @@ struct RandomIRBuilder {
fuzzerop::SourcePred Pred);
/// Return a uniformly choosen type from \c AllowedTypes
Type *randomType();
+ Function *createFunctionDeclaration(Module &M, uint64_t ArgNum);
+ Function *createFunctionDeclaration(Module &M);
+ Function *createFunctionDefinition(Module &M, uint64_t ArgNum);
+ Function *createFunctionDefinition(Module &M);
};
} // namespace llvm
diff --git a/llvm/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp
index 1e07acb5ae4d5..b896e3ca93fc6 100644
--- a/llvm/lib/FuzzMutate/IRMutator.cpp
+++ b/llvm/lib/FuzzMutate/IRMutator.cpp
@@ -31,26 +31,17 @@
using namespace llvm;
-static void createEmptyFunction(Module &M) {
- // TODO: Some arguments and a return value would probably be more interesting.
- LLVMContext &Context = M.getContext();
- Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Context), {},
- /*isVarArg=*/false),
- GlobalValue::ExternalLinkage, "f", &M);
- BasicBlock *BB = BasicBlock::Create(Context, "BB", F);
- ReturnInst::Create(Context, BB);
-}
-
void IRMutationStrategy::mutate(Module &M, RandomIRBuilder &IB) {
auto RS = makeSampler<Function *>(IB.Rand);
for (Function &F : M)
if (!F.isDeclaration())
RS.sample(&F, /*Weight=*/1);
- if (RS.isEmpty())
- createEmptyFunction(M);
- else
- mutate(*RS.getSelection(), IB);
+ while (RS.totalWeight() < IB.MinFunctionNum) {
+ Function *F = IB.createFunctionDefinition(M);
+ RS.sample(F, /*Weight=*/1);
+ }
+ mutate(*RS.getSelection(), IB);
}
void IRMutationStrategy::mutate(Function &F, RandomIRBuilder &IB) {
@@ -349,10 +340,65 @@ static uint64_t getUniqueCaseValue(SmallSet<uint64_t, 4> &CasesTaken,
return tmp;
}
+void InsertFunctionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
+ Module *M = BB.getParent()->getParent();
+ // If nullptr is selected, we will create a new function declaration.
+ SmallVector<Function *, 32> Functions({nullptr});
+ for (Function &F : M->functions()) {
+ Functions.push_back(&F);
+ }
+
+ auto RS = makeSampler(IB.Rand, Functions);
+ Function *F = RS.getSelection();
+ if (!F) {
+ F = IB.createFunctionDeclaration(*M);
+ }
+
+ FunctionType *FTy = F->getFunctionType();
+ SmallVector<fuzzerop::SourcePred, 2> SourcePreds;
+ if (!F->arg_empty()) {
+ for (Type *ArgTy : FTy->params()) {
+ SourcePreds.push_back(fuzzerop::onlyType(ArgTy));
+ }
+ }
+ bool isRetVoid = (F->getReturnType() == Type::getVoidTy(M->getContext()));
+ auto BuilderFunc = [FTy, F, isRetVoid](ArrayRef<Value *> Srcs,
+ Instruction *Inst) {
+ StringRef Name = isRetVoid ? nullptr : "C";
+ CallInst *Call = CallInst::Create(FTy, F, Srcs, Name, Inst);
+ // Don't return this call inst if it return void as it can't be sinked.
+ return isRetVoid ? nullptr : Call;
+ };
+
+ SmallVector<Instruction *, 32> Insts;
+ for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
+ Insts.push_back(&I);
+ if (Insts.size() < 1)
+ return;
+
+ // Choose an insertion point for our new call instruction.
+ uint64_t IP = uniform<uint64_t>(IB.Rand, 0, Insts.size() - 1);
+
+ auto InstsBefore = ArrayRef(Insts).slice(0, IP);
+ auto InstsAfter = ArrayRef(Insts).slice(IP);
+
+ // Choose a source, which will be used to constrain the operation selection.
+ SmallVector<Value *, 2> Srcs;
+
+ for (const auto &Pred : ArrayRef(SourcePreds)) {
+ Srcs.push_back(IB.findOrCreateSource(BB, InstsBefore, Srcs, Pred));
+ }
+
+ if (Value *Op = BuilderFunc(Srcs, Insts[IP])) {
+ // Find a sink and wire up the results of the operation.
+ IB.connectToSink(BB, InstsAfter, Op);
+ }
+}
+
void InsertCFGStrategy::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 : make_range(BB.getFirstInsertionPt(), BB.end()))
+ Insts.push_back(&I);
if (Insts.size() < 1)
return;
@@ -491,8 +537,8 @@ void InsertPHIStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
PHI->addIncoming(Src, Pred);
}
SmallVector<Instruction *, 32> InstsAfter;
- for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
- InstsAfter.push_back(&*I);
+ for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
+ InstsAfter.push_back(&I);
IB.connectToSink(BB, InstsAfter, PHI);
}
@@ -503,8 +549,8 @@ void SinkInstructionStrategy::mutate(Function &F, RandomIRBuilder &IB) {
}
void SinkInstructionStrategy::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 : make_range(BB.getFirstInsertionPt(), BB.end()))
+ Insts.push_back(&I);
if (Insts.size() < 1)
return;
// Choose an Instruction to mutate.
diff --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
index 3817bc054ec6c..4359ae6c4616b 100644
--- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
+++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
@@ -393,3 +393,48 @@ Type *RandomIRBuilder::randomType() {
uint64_t TyIdx = uniform<uint64_t>(Rand, 0, KnownTypes.size() - 1);
return KnownTypes[TyIdx];
}
+
+Function *RandomIRBuilder::createFunctionDeclaration(Module &M,
+ uint64_t ArgNum) {
+ Type *RetType = randomType();
+
+ SmallVector<Type *, 2> Args;
+ for (uint64_t i = 0; i < ArgNum; i++) {
+ Args.push_back(randomType());
+ }
+
+ Function *F = Function::Create(FunctionType::get(RetType, Args,
+ /*isVarArg=*/false),
+ GlobalValue::ExternalLinkage, "f", &M);
+ return F;
+}
+Function *RandomIRBuilder::createFunctionDeclaration(Module &M) {
+ return createFunctionDeclaration(
+ M, uniform<uint64_t>(Rand, MinArgNum, MaxArgNum));
+}
+
+Function *RandomIRBuilder::createFunctionDefinition(Module &M,
+ uint64_t ArgNum) {
+ Function *F = this->createFunctionDeclaration(M, ArgNum);
+
+ // TODO: Some arguments and a return value would probably be more
+ // interesting.
+ LLVMContext &Context = M.getContext();
+ DataLayout DL(&M);
+ BasicBlock *BB = BasicBlock::Create(Context, "BB", F);
+ Type *RetTy = F->getReturnType();
+ if (RetTy != Type::getVoidTy(Context)) {
+ Instruction *RetAlloca =
+ new AllocaInst(RetTy, DL.getAllocaAddrSpace(), "RP", BB);
+ Instruction *RetLoad = new LoadInst(RetTy, RetAlloca, "", BB);
+ ReturnInst::Create(Context, RetLoad, BB);
+ } else {
+ ReturnInst::Create(Context, BB);
+ }
+
+ return F;
+}
+Function *RandomIRBuilder::createFunctionDefinition(Module &M) {
+ return createFunctionDefinition(
+ M, uniform<uint64_t>(Rand, MinArgNum, MaxArgNum));
+}
diff --git a/llvm/unittests/FuzzMutate/StrategiesTest.cpp b/llvm/unittests/FuzzMutate/StrategiesTest.cpp
index 92d7fc112020e..5b87b9c6a7b87 100644
--- a/llvm/unittests/FuzzMutate/StrategiesTest.cpp
+++ b/llvm/unittests/FuzzMutate/StrategiesTest.cpp
@@ -348,6 +348,21 @@ TEST(InstModificationIRStrategyTest, DidntShuffleFRem) {
}";
VerfyDivDidntShuffle(Source);
}
+
+TEST(FunctionIRStrategy, Func) {
+ LLVMContext Ctx;
+ const char *Source = "";
+ auto Mutator = createMutator<InsertFunctionStrategy>();
+ ASSERT_TRUE(Mutator);
+
+ auto M = parseAssembly(Source, Ctx);
+ srand(Seed);
+ for (int i = 0; i < 100; i++) {
+ Mutator->mutateModule(*M, rand(), 0, 1024);
+ EXPECT_TRUE(!verifyModule(*M, &errs()));
+ }
+}
+
TEST(InstModificationIRStrategy, Exact) {
LLVMContext Ctx;
StringRef Source = "\n\
More information about the llvm-commits
mailing list