Skip to content

Commit 0f87ccd

Browse files
committed
Re-apply "Introduce FuzzMutate library"
Same as r311392 with some fixes for library dependencies. Thanks to Chapuni for helping work those out! Original commit message: This introduces the FuzzMutate library, which provides structured fuzzing for LLVM IR, as described in my EuroLLVM 2017 talk. Most of the basic mutators to inject and delete IR are provided, with support for most basic operations. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311402 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 463fa38 commit 0f87ccd

17 files changed

+1624
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//===-- IRMutator.h - Mutation engine for fuzzing IR ------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// Provides the IRMutator class, which drives mutations on IR based on a
11+
// configurable set of strategies. Some common strategies are also included
12+
// here.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef LLVM_FUZZMUTATE_IRMUTATOR_H
17+
#define LLVM_FUZZMUTATE_IRMUTATOR_H
18+
19+
#include "llvm/FuzzMutate/OpDescriptor.h"
20+
#include "llvm/Support/ErrorHandling.h"
21+
22+
namespace llvm {
23+
class BasicBlock;
24+
class Function;
25+
class Instruction;
26+
class Module;
27+
28+
struct RandomIRBuilder;
29+
30+
/// Base class for describing how to mutate a module. mutation functions for
31+
/// each IR unit forward to the contained unit.
32+
class IRMutationStrategy {
33+
public:
34+
virtual ~IRMutationStrategy() = default;
35+
36+
/// Provide a weight to bias towards choosing this strategy for a mutation.
37+
///
38+
/// The value of the weight is arbitrary, but a good default is "the number of
39+
/// distinct ways in which this strategy can mutate a unit". This can also be
40+
/// used to prefer strategies that shrink the overall size of the result when
41+
/// we start getting close to \c MaxSize.
42+
virtual uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
43+
uint64_t CurrentWeight) = 0;
44+
45+
/// @{
46+
/// Mutators for each IR unit. By default these forward to a contained
47+
/// instance of the next smaller unit.
48+
virtual void mutate(Module &M, RandomIRBuilder &IB);
49+
virtual void mutate(Function &F, RandomIRBuilder &IB);
50+
virtual void mutate(BasicBlock &BB, RandomIRBuilder &IB);
51+
virtual void mutate(Instruction &I, RandomIRBuilder &IB) {
52+
llvm_unreachable("Strategy does not implement any mutators");
53+
}
54+
/// @}
55+
};
56+
57+
using TypeGetter = std::function<Type *(LLVMContext &)>;
58+
59+
/// Entry point for configuring and running IR mutations.
60+
class IRMutator {
61+
std::vector<TypeGetter> AllowedTypes;
62+
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
63+
64+
public:
65+
IRMutator(std::vector<TypeGetter> &&AllowedTypes,
66+
std::vector<std::unique_ptr<IRMutationStrategy>> &&Strategies)
67+
: AllowedTypes(std::move(AllowedTypes)),
68+
Strategies(std::move(Strategies)) {}
69+
70+
void mutateModule(Module &M, int Seed, size_t CurSize, size_t MaxSize);
71+
};
72+
73+
/// Strategy that injects operations into the function.
74+
class InjectorIRStrategy : public IRMutationStrategy {
75+
std::vector<fuzzerop::OpDescriptor> Operations;
76+
77+
fuzzerop::OpDescriptor chooseOperation(Value *Src, RandomIRBuilder &IB);
78+
79+
public:
80+
InjectorIRStrategy(std::vector<fuzzerop::OpDescriptor> &&Operations)
81+
: Operations(std::move(Operations)) {}
82+
static std::vector<fuzzerop::OpDescriptor> getDefaultOps();
83+
84+
uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
85+
uint64_t CurrentWeight) override {
86+
return Operations.size();
87+
}
88+
89+
using IRMutationStrategy::mutate;
90+
void mutate(Function &F, RandomIRBuilder &IB) override;
91+
void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
92+
};
93+
94+
class InstDeleterIRStrategy : public IRMutationStrategy {
95+
public:
96+
uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
97+
uint64_t CurrentWeight) override;
98+
99+
using IRMutationStrategy::mutate;
100+
void mutate(Function &F, RandomIRBuilder &IB) override;
101+
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
102+
};
103+
104+
} // end llvm namespace
105+
106+
#endif // LLVM_FUZZMUTATE_IRMUTATOR_H
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
//===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// Provides the fuzzerop::Descriptor class and related tools for describing
11+
// operations an IR fuzzer can work with.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
16+
#define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
17+
18+
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/ADT/STLExtras.h"
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/IR/Constants.h"
22+
#include "llvm/IR/DerivedTypes.h"
23+
#include "llvm/IR/Type.h"
24+
#include "llvm/IR/Value.h"
25+
#include <functional>
26+
27+
namespace llvm {
28+
namespace fuzzerop {
29+
30+
/// @{
31+
/// Populate a small list of potentially interesting constants of a given type.
32+
void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
33+
std::vector<Constant *> makeConstantsWithType(Type *T);
34+
/// @}
35+
36+
/// A matcher/generator for finding suitable values for the next source in an
37+
/// operation's partially completed argument list.
38+
///
39+
/// Given that we're building some operation X and may have already filled some
40+
/// subset of its operands, this predicate determines if some value New is
41+
/// suitable for the next operand or generates a set of values that are
42+
/// suitable.
43+
class SourcePred {
44+
public:
45+
/// Given a list of already selected operands, returns whether a given new
46+
/// operand is suitable for the next operand.
47+
using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
48+
/// Given a list of already selected operands and a set of valid base types
49+
/// for a fuzzer, generates a list of constants that could be used for the
50+
/// next operand.
51+
using MakeT = std::function<std::vector<Constant *>(
52+
ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
53+
54+
private:
55+
PredT Pred;
56+
MakeT Make;
57+
58+
public:
59+
/// Create a fully general source predicate.
60+
SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
61+
SourcePred(PredT Pred, NoneType) : Pred(Pred) {
62+
Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
63+
// Default filter just calls Pred on each of the base types.
64+
std::vector<Constant *> Result;
65+
for (Type *T : BaseTypes) {
66+
Constant *V = UndefValue::get(T);
67+
if (Pred(Cur, V))
68+
makeConstantsWithType(T, Result);
69+
}
70+
if (Result.empty())
71+
report_fatal_error("Predicate does not match for base types");
72+
return Result;
73+
};
74+
}
75+
76+
/// Returns true if \c New is compatible for the argument after \c Cur
77+
bool matches(ArrayRef<Value *> Cur, const Value *New) {
78+
return Pred(Cur, New);
79+
}
80+
81+
/// Generates a list of potential values for the argument after \c Cur.
82+
std::vector<Constant *> generate(ArrayRef<Value *> Cur,
83+
ArrayRef<Type *> BaseTypes) {
84+
return Make(Cur, BaseTypes);
85+
}
86+
};
87+
88+
/// A description of some operation we can build while fuzzing IR.
89+
struct OpDescriptor {
90+
unsigned Weight;
91+
SmallVector<SourcePred, 2> SourcePreds;
92+
std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
93+
};
94+
95+
static inline SourcePred onlyType(Type *Only) {
96+
auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
97+
return V->getType() == Only;
98+
};
99+
auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
100+
return makeConstantsWithType(Only);
101+
};
102+
return {Pred, Make};
103+
}
104+
105+
static inline SourcePred anyType() {
106+
auto Pred = [](ArrayRef<Value *>, const Value *V) {
107+
return !V->getType()->isVoidTy();
108+
};
109+
auto Make = None;
110+
return {Pred, Make};
111+
}
112+
113+
static inline SourcePred anyIntType() {
114+
auto Pred = [](ArrayRef<Value *>, const Value *V) {
115+
return V->getType()->isIntegerTy();
116+
};
117+
auto Make = None;
118+
return {Pred, Make};
119+
}
120+
121+
static inline SourcePred anyFloatType() {
122+
auto Pred = [](ArrayRef<Value *>, const Value *V) {
123+
return V->getType()->isFloatingPointTy();
124+
};
125+
auto Make = None;
126+
return {Pred, Make};
127+
}
128+
129+
static inline SourcePred anyPtrType() {
130+
auto Pred = [](ArrayRef<Value *>, const Value *V) {
131+
return V->getType()->isPointerTy();
132+
};
133+
auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
134+
std::vector<Constant *> Result;
135+
// TODO: Should these point at something?
136+
for (Type *T : Ts)
137+
Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
138+
return Result;
139+
};
140+
return {Pred, Make};
141+
}
142+
143+
static inline SourcePred anyAggregateType() {
144+
auto Pred = [](ArrayRef<Value *>, const Value *V) {
145+
return V->getType()->isAggregateType();
146+
};
147+
// TODO: For now we only find aggregates in BaseTypes. It might be better to
148+
// manufacture them out of the base types in some cases.
149+
auto Find = None;
150+
return {Pred, Find};
151+
}
152+
153+
static inline SourcePred anyVectorType() {
154+
auto Pred = [](ArrayRef<Value *>, const Value *V) {
155+
return V->getType()->isVectorTy();
156+
};
157+
// TODO: For now we only find vectors in BaseTypes. It might be better to
158+
// manufacture vectors out of the base types, but it's tricky to be sure
159+
// that's actually a reasonable type.
160+
auto Make = None;
161+
return {Pred, Make};
162+
}
163+
164+
/// Match values that have the same type as the first source.
165+
static inline SourcePred matchFirstType() {
166+
auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
167+
assert(!Cur.empty() && "No first source yet");
168+
return V->getType() == Cur[0]->getType();
169+
};
170+
auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
171+
assert(!Cur.empty() && "No first source yet");
172+
return makeConstantsWithType(Cur[0]->getType());
173+
};
174+
return {Pred, Make};
175+
}
176+
177+
/// Match values that have the first source's scalar type.
178+
static inline SourcePred matchScalarOfFirstType() {
179+
auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
180+
assert(!Cur.empty() && "No first source yet");
181+
return V->getType() == Cur[0]->getType()->getScalarType();
182+
};
183+
auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
184+
assert(!Cur.empty() && "No first source yet");
185+
return makeConstantsWithType(Cur[0]->getType()->getScalarType());
186+
};
187+
return {Pred, Make};
188+
}
189+
190+
} // end fuzzerop namespace
191+
} // end llvm namespace
192+
193+
#endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===-- Operations.h - ----------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// Implementations of common fuzzer operation descriptors for building an IR
11+
// mutator.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_FUZZMUTATE_OPERATIONS_H
16+
#define LLVM_FUZZMUTATE_OPERATIONS_H
17+
18+
#include "llvm/FuzzMutate/OpDescriptor.h"
19+
#include "llvm/IR/InstrTypes.h"
20+
#include "llvm/IR/Instruction.h"
21+
22+
namespace llvm {
23+
24+
/// Getters for the default sets of operations, per general category.
25+
/// @{
26+
void describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> &Ops);
27+
void describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> &Ops);
28+
void describeFuzzerControlFlowOps(std::vector<fuzzerop::OpDescriptor> &Ops);
29+
void describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops);
30+
void describeFuzzerAggregateOps(std::vector<fuzzerop::OpDescriptor> &Ops);
31+
void describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops);
32+
/// @}
33+
34+
namespace fuzzerop {
35+
36+
/// Descriptors for individual operations.
37+
/// @{
38+
OpDescriptor binOpDescriptor(unsigned Weight, Instruction::BinaryOps Op);
39+
OpDescriptor cmpOpDescriptor(unsigned Weight, Instruction::OtherOps CmpOp,
40+
CmpInst::Predicate Pred);
41+
OpDescriptor splitBlockDescriptor(unsigned Weight);
42+
OpDescriptor gepDescriptor(unsigned Weight);
43+
OpDescriptor extractValueDescriptor(unsigned Weight);
44+
OpDescriptor insertValueDescriptor(unsigned Weight);
45+
OpDescriptor extractElementDescriptor(unsigned Weight);
46+
OpDescriptor insertElementDescriptor(unsigned Weight);
47+
OpDescriptor shuffleVectorDescriptor(unsigned Weight);
48+
/// @}
49+
50+
} // end fuzzerop namespace
51+
52+
} // end llvm namespace
53+
54+
#endif // LLVM_FUZZMUTATE_OPERATIONS_H

0 commit comments

Comments
 (0)