mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[libFuzzer] allow users to supply their own implementation of rand
llvm-svn: 243078
This commit is contained in:
parent
d193d66cf2
commit
02e05d0662
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user