[libFuzzer] allow users to supply their own implementation of rand

llvm-svn: 243078
This commit is contained in:
Kostya Serebryany 2015-07-24 01:06:40 +00:00
parent d193d66cf2
commit 02e05d0662
10 changed files with 85 additions and 32 deletions

View File

@ -18,9 +18,9 @@ namespace fuzzer {
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
size_t CrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize) {
uint8_t *Out, size_t MaxOutSize, FuzzerRandomBase &Rand) {
assert(Size1 || Size2);
MaxOutSize = rand() % MaxOutSize + 1;
MaxOutSize = Rand(MaxOutSize) + 1;
size_t OutPos = 0;
size_t Pos1 = 0;
size_t Pos2 = 0;
@ -34,7 +34,7 @@ size_t CrossOver(const uint8_t *Data1, size_t Size1,
if (*InPos < InSize) {
size_t InSizeLeft = InSize - *InPos;
size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
size_t ExtraSize = rand() % MaxExtraSize + 1;
size_t ExtraSize = Rand(MaxExtraSize) + 1;
memcpy(Out + OutPos, Data + *InPos, ExtraSize);
OutPos += ExtraSize;
(*InPos) += ExtraSize;

View File

@ -202,7 +202,8 @@ int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
}
int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
SimpleUserSuppliedFuzzer SUSF(Callback);
FuzzerRandomLibc Rand(0);
SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
return FuzzerDriver(argc, argv, SUSF);
}
@ -257,7 +258,7 @@ int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) {
Seed = time(0) * 10000 + getpid();
if (Flags.verbosity)
Printf("Seed: %u\n", Seed);
srand(Seed);
USF.GetRand().ResetSeed(Seed);
// Timer
if (Flags.timeout > 0)

View File

@ -14,14 +14,30 @@
#include "FuzzerInternal.h"
namespace fuzzer {
void FuzzerRandomLibc::ResetSeed(int seed) { srand(seed); }
size_t FuzzerRandomLibc::Rand() { return rand(); }
UserSuppliedFuzzer::UserSuppliedFuzzer()
: OwnRand(true), Rand(new FuzzerRandomLibc(0)) {}
UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand) : Rand(Rand) {}
UserSuppliedFuzzer::~UserSuppliedFuzzer() {
if (OwnRand)
delete Rand;
}
size_t UserSuppliedFuzzer::BasicMutate(uint8_t *Data, size_t Size,
size_t MaxSize) {
return ::fuzzer::Mutate(Data, Size, MaxSize);
return ::fuzzer::Mutate(Data, Size, MaxSize, *Rand);
}
size_t UserSuppliedFuzzer::BasicCrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize) {
return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize,
*Rand);
}
} // namespace fuzzer.

View File

@ -42,6 +42,26 @@ int main(int argc, char **argv) {
*/
int FuzzerDriver(int argc, char **argv, UserCallback Callback);
class FuzzerRandomBase {
public:
FuzzerRandomBase(){}
virtual ~FuzzerRandomBase(){};
virtual void ResetSeed(int seed) = 0;
// Return a random number.
virtual size_t Rand() = 0;
// Return a random number in range [0,n).
size_t operator()(size_t n) { return Rand() % n; }
bool RandBool() { return Rand() % 2; }
};
class FuzzerRandomLibc : public FuzzerRandomBase {
public:
FuzzerRandomLibc(int seed) { ResetSeed(seed); }
void ResetSeed(int seed) override;
~FuzzerRandomLibc() override {}
size_t Rand() override;
};
/** An abstract class that allows to use user-supplied mutators with libFuzzer.
Usage:
@ -50,6 +70,7 @@ Usage:
#include "FuzzerInterface.h"
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
public:
MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
// Must define the target function.
void TargetFunction(...) { ... }
// Optionally define the mutator.
@ -66,6 +87,8 @@ int main(int argc, char **argv) {
*/
class UserSuppliedFuzzer {
public:
UserSuppliedFuzzer(); // Deprecated, don't use.
UserSuppliedFuzzer(FuzzerRandomBase *Rand);
/// Executes the target function on 'Size' bytes of 'Data'.
virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0;
/// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes,
@ -80,7 +103,9 @@ class UserSuppliedFuzzer {
uint8_t *Out, size_t MaxOutSize) {
return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
}
virtual ~UserSuppliedFuzzer() {}
virtual ~UserSuppliedFuzzer();
FuzzerRandomBase &GetRand() { return *Rand; }
protected:
/// These can be called internally by Mutate and CrossOver.
@ -88,6 +113,9 @@ class UserSuppliedFuzzer {
size_t BasicCrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize);
private:
bool OwnRand = false;
FuzzerRandomBase *Rand;
};
/// Runs the fuzzing with the UserSuppliedFuzzer.

View File

@ -33,10 +33,12 @@ void CopyFileToErr(const std::string &Path);
std::string DirPlusFile(const std::string &DirPath,
const std::string &FileName);
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
FuzzerRandomBase &Rand);
size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
size_t Size2, uint8_t *Out, size_t MaxOutSize);
size_t Size2, uint8_t *Out, size_t MaxOutSize,
FuzzerRandomBase &Rand);
void Printf(const char *Fmt, ...);
void Print(const Unit &U, const char *PrintAfter = "");
@ -155,7 +157,8 @@ class Fuzzer {
class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
public:
SimpleUserSuppliedFuzzer(UserCallback Callback) : Callback(Callback) {}
SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback)
: UserSuppliedFuzzer(Rand), Callback(Callback) {}
virtual void TargetFunction(const uint8_t *Data, size_t Size) {
return Callback(Data, Size);
}

View File

@ -113,14 +113,14 @@ void Fuzzer::RereadOutputCorpus() {
void Fuzzer::ShuffleAndMinimize() {
size_t MaxCov = 0;
bool PreferSmall =
(Options.PreferSmallDuringInitialShuffle == 1 ||
(Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2));
bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
(Options.PreferSmallDuringInitialShuffle == -1 &&
USF.GetRand().RandBool()));
if (Options.Verbosity)
Printf("PreferSmall: %d\n", PreferSmall);
PrintStats("READ ", 0);
std::vector<Unit> NewCorpus;
std::random_shuffle(Corpus.begin(), Corpus.end());
std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand());
if (PreferSmall)
std::stable_sort(
Corpus.begin(), Corpus.end(),

View File

@ -15,8 +15,8 @@
namespace fuzzer {
static char FlipRandomBit(char X) {
int Bit = rand() % 8;
static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
int Bit = Rand(8);
char Mask = 1 << Bit;
char R;
if (X & (1 << Bit))
@ -27,24 +27,25 @@ static char FlipRandomBit(char X) {
return R;
}
static char RandCh() {
if (rand() % 2) return rand();
static char RandCh(FuzzerRandomBase &Rand) {
if (Rand.RandBool()) return Rand(256);
const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
return Special[rand() % (sizeof(Special) - 1)];
return Special[Rand(sizeof(Special) - 1)];
}
// Mutates Data in place, returns new size.
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
FuzzerRandomBase &Rand) {
assert(MaxSize > 0);
assert(Size <= MaxSize);
if (Size == 0) {
for (size_t i = 0; i < MaxSize; i++)
Data[i] = RandCh();
Data[i] = RandCh(Rand);
return MaxSize;
}
assert(Size > 0);
size_t Idx = rand() % Size;
switch (rand() % 3) {
size_t Idx = Rand(Size);
switch (Rand(3)) {
case 0:
if (Size > 1) {
// Erase Data[Idx].
@ -56,12 +57,12 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
if (Size < MaxSize) {
// Insert new value at Data[Idx].
memmove(Data + Idx + 1, Data + Idx, Size - Idx);
Data[Idx] = RandCh();
Data[Idx] = RandCh(Rand);
}
Data[Idx] = RandCh();
Data[Idx] = RandCh(Rand);
break;
case 2:
Data[Idx] = FlipRandomBit(Data[Idx]);
Data[Idx] = FlipRandomBit(Data[Idx], Rand);
break;
}
assert(Size > 0);

View File

@ -191,9 +191,9 @@ class TraceState {
Mutations.clear();
}
size_t StopTraceRecording() {
size_t StopTraceRecording(FuzzerRandomBase &Rand) {
RecordingTraces = false;
std::random_shuffle(Mutations.begin(), Mutations.end());
std::random_shuffle(Mutations.begin(), Mutations.end(), Rand);
return Mutations.size();
}
@ -302,7 +302,7 @@ void Fuzzer::StartTraceRecording() {
size_t Fuzzer::StopTraceRecording() {
if (!TS) return 0;
return TS->StopTraceRecording();
return TS->StopTraceRecording(USF.GetRand());
}
void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) {

View File

@ -10,6 +10,7 @@ extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
TEST(Fuzzer, CrossOver) {
using namespace fuzzer;
FuzzerRandomLibc Rand(0);
Unit A({0, 1, 2}), B({5, 6, 7});
Unit C;
Unit Expected[] = {
@ -53,7 +54,7 @@ TEST(Fuzzer, CrossOver) {
for (int Iter = 0; Iter < 3000; Iter++) {
C.resize(Len);
size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(),
C.data(), C.size());
C.data(), C.size(), Rand);
C.resize(NewSize);
FoundUnits.insert(C);
}

View File

@ -14,6 +14,8 @@ static const uint64_t kMagic = 8860221463604ULL;
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
public:
MyFuzzer(fuzzer::FuzzerRandomBase *Rand)
: fuzzer::UserSuppliedFuzzer(Rand) {}
void TargetFunction(const uint8_t *Data, size_t Size) {
if (Size <= 10) return;
if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
@ -42,6 +44,7 @@ class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
};
int main(int argc, char **argv) {
MyFuzzer F;
fuzzer::FuzzerRandomLibc Rand(0);
MyFuzzer F(&Rand);
fuzzer::FuzzerDriver(argc, argv, F);
}