Skip to content

Commit 6998b34

Browse files
committed
[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
1 parent 038536a commit 6998b34

File tree

5 files changed

+149
-21
lines changed

5 files changed

+149
-21
lines changed

llvm/include/llvm/FuzzMutate/IRMutator.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,20 @@ class InstModificationIRStrategy : public IRMutationStrategy {
118118
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
119119
};
120120

121+
/// Strategy that generates new function calls and inserts function signatures
122+
/// to the modules. If any signatures are present in the module it will be
123+
/// called.
124+
class InsertFunctionStrategy : public IRMutationStrategy {
125+
public:
126+
uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
127+
uint64_t CurrentWeight) override {
128+
return 10;
129+
}
130+
131+
using IRMutationStrategy::mutate;
132+
void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
133+
};
134+
121135
/// Strategy to split a random block and insert a random CFG in between.
122136
class InsertCFGStrategy : public IRMutationStrategy {
123137
private:

llvm/include/llvm/FuzzMutate/RandomIRBuilder.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class Function;
2424
class GlobalVariable;
2525
class Instruction;
2626
class LLVMContext;
27+
class Module;
2728
class Type;
2829
class Value;
29-
class Module;
3030

3131
namespace fuzzerop {
3232
class SourcePred;
@@ -38,6 +38,10 @@ struct RandomIRBuilder {
3838
RandomEngine Rand;
3939
SmallVector<Type *, 16> KnownTypes;
4040

41+
uint64_t MinArgNum = 0;
42+
uint64_t MaxArgNum = 5;
43+
uint64_t MinFunctionNum = 1;
44+
4145
RandomIRBuilder(int Seed, ArrayRef<Type *> AllowedTypes)
4246
: Rand(Seed), KnownTypes(AllowedTypes.begin(), AllowedTypes.end()) {}
4347

@@ -98,6 +102,10 @@ struct RandomIRBuilder {
98102
fuzzerop::SourcePred Pred);
99103
/// Return a uniformly choosen type from \c AllowedTypes
100104
Type *randomType();
105+
Function *createFunctionDeclaration(Module &M, uint64_t ArgNum);
106+
Function *createFunctionDeclaration(Module &M);
107+
Function *createFunctionDefinition(Module &M, uint64_t ArgNum);
108+
Function *createFunctionDefinition(Module &M);
101109
};
102110

103111
} // namespace llvm

llvm/lib/FuzzMutate/IRMutator.cpp

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,17 @@
3131

3232
using namespace llvm;
3333

34-
static void createEmptyFunction(Module &M) {
35-
// TODO: Some arguments and a return value would probably be more interesting.
36-
LLVMContext &Context = M.getContext();
37-
Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Context), {},
38-
/*isVarArg=*/false),
39-
GlobalValue::ExternalLinkage, "f", &M);
40-
BasicBlock *BB = BasicBlock::Create(Context, "BB", F);
41-
ReturnInst::Create(Context, BB);
42-
}
43-
4434
void IRMutationStrategy::mutate(Module &M, RandomIRBuilder &IB) {
4535
auto RS = makeSampler<Function *>(IB.Rand);
4636
for (Function &F : M)
4737
if (!F.isDeclaration())
4838
RS.sample(&F, /*Weight=*/1);
4939

50-
if (RS.isEmpty())
51-
createEmptyFunction(M);
52-
else
53-
mutate(*RS.getSelection(), IB);
40+
while (RS.totalWeight() < IB.MinFunctionNum) {
41+
Function *F = IB.createFunctionDefinition(M);
42+
RS.sample(F, /*Weight=*/1);
43+
}
44+
mutate(*RS.getSelection(), IB);
5445
}
5546

5647
void IRMutationStrategy::mutate(Function &F, RandomIRBuilder &IB) {
@@ -349,10 +340,65 @@ static uint64_t getUniqueCaseValue(SmallSet<uint64_t, 4> &CasesTaken,
349340
return tmp;
350341
}
351342

343+
void InsertFunctionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
344+
Module *M = BB.getParent()->getParent();
345+
// If nullptr is selected, we will create a new function declaration.
346+
SmallVector<Function *, 32> Functions({nullptr});
347+
for (Function &F : M->functions()) {
348+
Functions.push_back(&F);
349+
}
350+
351+
auto RS = makeSampler(IB.Rand, Functions);
352+
Function *F = RS.getSelection();
353+
if (!F) {
354+
F = IB.createFunctionDeclaration(*M);
355+
}
356+
357+
FunctionType *FTy = F->getFunctionType();
358+
SmallVector<fuzzerop::SourcePred, 2> SourcePreds;
359+
if (!F->arg_empty()) {
360+
for (Type *ArgTy : FTy->params()) {
361+
SourcePreds.push_back(fuzzerop::onlyType(ArgTy));
362+
}
363+
}
364+
bool isRetVoid = (F->getReturnType() == Type::getVoidTy(M->getContext()));
365+
auto BuilderFunc = [FTy, F, isRetVoid](ArrayRef<Value *> Srcs,
366+
Instruction *Inst) {
367+
StringRef Name = isRetVoid ? nullptr : "C";
368+
CallInst *Call = CallInst::Create(FTy, F, Srcs, Name, Inst);
369+
// Don't return this call inst if it return void as it can't be sinked.
370+
return isRetVoid ? nullptr : Call;
371+
};
372+
373+
SmallVector<Instruction *, 32> Insts;
374+
for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
375+
Insts.push_back(&I);
376+
if (Insts.size() < 1)
377+
return;
378+
379+
// Choose an insertion point for our new call instruction.
380+
uint64_t IP = uniform<uint64_t>(IB.Rand, 0, Insts.size() - 1);
381+
382+
auto InstsBefore = ArrayRef(Insts).slice(0, IP);
383+
auto InstsAfter = ArrayRef(Insts).slice(IP);
384+
385+
// Choose a source, which will be used to constrain the operation selection.
386+
SmallVector<Value *, 2> Srcs;
387+
388+
for (const auto &Pred : ArrayRef(SourcePreds)) {
389+
Srcs.push_back(IB.findOrCreateSource(BB, InstsBefore, Srcs, Pred));
390+
}
391+
392+
if (Value *Op = BuilderFunc(Srcs, Insts[IP])) {
393+
// Find a sink and wire up the results of the operation.
394+
IB.connectToSink(BB, InstsAfter, Op);
395+
}
396+
}
397+
352398
void InsertCFGStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
353399
SmallVector<Instruction *, 32> Insts;
354-
for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
355-
Insts.push_back(&*I);
400+
for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
401+
Insts.push_back(&I);
356402
if (Insts.size() < 1)
357403
return;
358404

@@ -491,8 +537,8 @@ void InsertPHIStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
491537
PHI->addIncoming(Src, Pred);
492538
}
493539
SmallVector<Instruction *, 32> InstsAfter;
494-
for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
495-
InstsAfter.push_back(&*I);
540+
for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
541+
InstsAfter.push_back(&I);
496542
IB.connectToSink(BB, InstsAfter, PHI);
497543
}
498544

@@ -503,8 +549,8 @@ void SinkInstructionStrategy::mutate(Function &F, RandomIRBuilder &IB) {
503549
}
504550
void SinkInstructionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
505551
SmallVector<Instruction *, 32> Insts;
506-
for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
507-
Insts.push_back(&*I);
552+
for (Instruction &I : make_range(BB.getFirstInsertionPt(), BB.end()))
553+
Insts.push_back(&I);
508554
if (Insts.size() < 1)
509555
return;
510556
// Choose an Instruction to mutate.

llvm/lib/FuzzMutate/RandomIRBuilder.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,48 @@ Type *RandomIRBuilder::randomType() {
393393
uint64_t TyIdx = uniform<uint64_t>(Rand, 0, KnownTypes.size() - 1);
394394
return KnownTypes[TyIdx];
395395
}
396+
397+
Function *RandomIRBuilder::createFunctionDeclaration(Module &M,
398+
uint64_t ArgNum) {
399+
Type *RetType = randomType();
400+
401+
SmallVector<Type *, 2> Args;
402+
for (uint64_t i = 0; i < ArgNum; i++) {
403+
Args.push_back(randomType());
404+
}
405+
406+
Function *F = Function::Create(FunctionType::get(RetType, Args,
407+
/*isVarArg=*/false),
408+
GlobalValue::ExternalLinkage, "f", &M);
409+
return F;
410+
}
411+
Function *RandomIRBuilder::createFunctionDeclaration(Module &M) {
412+
return createFunctionDeclaration(
413+
M, uniform<uint64_t>(Rand, MinArgNum, MaxArgNum));
414+
}
415+
416+
Function *RandomIRBuilder::createFunctionDefinition(Module &M,
417+
uint64_t ArgNum) {
418+
Function *F = this->createFunctionDeclaration(M, ArgNum);
419+
420+
// TODO: Some arguments and a return value would probably be more
421+
// interesting.
422+
LLVMContext &Context = M.getContext();
423+
DataLayout DL(&M);
424+
BasicBlock *BB = BasicBlock::Create(Context, "BB", F);
425+
Type *RetTy = F->getReturnType();
426+
if (RetTy != Type::getVoidTy(Context)) {
427+
Instruction *RetAlloca =
428+
new AllocaInst(RetTy, DL.getAllocaAddrSpace(), "RP", BB);
429+
Instruction *RetLoad = new LoadInst(RetTy, RetAlloca, "", BB);
430+
ReturnInst::Create(Context, RetLoad, BB);
431+
} else {
432+
ReturnInst::Create(Context, BB);
433+
}
434+
435+
return F;
436+
}
437+
Function *RandomIRBuilder::createFunctionDefinition(Module &M) {
438+
return createFunctionDefinition(
439+
M, uniform<uint64_t>(Rand, MinArgNum, MaxArgNum));
440+
}

llvm/unittests/FuzzMutate/StrategiesTest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,21 @@ TEST(InstModificationIRStrategyTest, DidntShuffleFRem) {
348348
}";
349349
VerfyDivDidntShuffle(Source);
350350
}
351+
352+
TEST(FunctionIRStrategy, Func) {
353+
LLVMContext Ctx;
354+
const char *Source = "";
355+
auto Mutator = createMutator<InsertFunctionStrategy>();
356+
ASSERT_TRUE(Mutator);
357+
358+
auto M = parseAssembly(Source, Ctx);
359+
srand(Seed);
360+
for (int i = 0; i < 100; i++) {
361+
Mutator->mutateModule(*M, rand(), 0, 1024);
362+
EXPECT_TRUE(!verifyModule(*M, &errs()));
363+
}
364+
}
365+
351366
TEST(InstModificationIRStrategy, Exact) {
352367
LLVMContext Ctx;
353368
StringRef Source = "\n\

0 commit comments

Comments
 (0)