mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-10-06 02:17:20 +00:00
[libFuzzer] allow users to supply their own implementation of rand
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243078 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -18,9 +18,9 @@ namespace fuzzer {
|
|||||||
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
|
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
|
||||||
size_t CrossOver(const uint8_t *Data1, size_t Size1,
|
size_t CrossOver(const uint8_t *Data1, size_t Size1,
|
||||||
const uint8_t *Data2, size_t Size2,
|
const uint8_t *Data2, size_t Size2,
|
||||||
uint8_t *Out, size_t MaxOutSize) {
|
uint8_t *Out, size_t MaxOutSize, FuzzerRandomBase &Rand) {
|
||||||
assert(Size1 || Size2);
|
assert(Size1 || Size2);
|
||||||
MaxOutSize = rand() % MaxOutSize + 1;
|
MaxOutSize = Rand(MaxOutSize) + 1;
|
||||||
size_t OutPos = 0;
|
size_t OutPos = 0;
|
||||||
size_t Pos1 = 0;
|
size_t Pos1 = 0;
|
||||||
size_t Pos2 = 0;
|
size_t Pos2 = 0;
|
||||||
@@ -34,7 +34,7 @@ size_t CrossOver(const uint8_t *Data1, size_t Size1,
|
|||||||
if (*InPos < InSize) {
|
if (*InPos < InSize) {
|
||||||
size_t InSizeLeft = InSize - *InPos;
|
size_t InSizeLeft = InSize - *InPos;
|
||||||
size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
|
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);
|
memcpy(Out + OutPos, Data + *InPos, ExtraSize);
|
||||||
OutPos += ExtraSize;
|
OutPos += ExtraSize;
|
||||||
(*InPos) += ExtraSize;
|
(*InPos) += ExtraSize;
|
||||||
|
@@ -202,7 +202,8 @@ int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
|
int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
|
||||||
SimpleUserSuppliedFuzzer SUSF(Callback);
|
FuzzerRandomLibc Rand(0);
|
||||||
|
SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
|
||||||
return FuzzerDriver(argc, argv, SUSF);
|
return FuzzerDriver(argc, argv, SUSF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) {
|
|||||||
Seed = time(0) * 10000 + getpid();
|
Seed = time(0) * 10000 + getpid();
|
||||||
if (Flags.verbosity)
|
if (Flags.verbosity)
|
||||||
Printf("Seed: %u\n", Seed);
|
Printf("Seed: %u\n", Seed);
|
||||||
srand(Seed);
|
USF.GetRand().ResetSeed(Seed);
|
||||||
|
|
||||||
// Timer
|
// Timer
|
||||||
if (Flags.timeout > 0)
|
if (Flags.timeout > 0)
|
||||||
|
@@ -14,14 +14,30 @@
|
|||||||
#include "FuzzerInternal.h"
|
#include "FuzzerInternal.h"
|
||||||
|
|
||||||
namespace fuzzer {
|
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 UserSuppliedFuzzer::BasicMutate(uint8_t *Data, size_t Size,
|
||||||
size_t MaxSize) {
|
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,
|
size_t UserSuppliedFuzzer::BasicCrossOver(const uint8_t *Data1, size_t Size1,
|
||||||
const uint8_t *Data2, size_t Size2,
|
const uint8_t *Data2, size_t Size2,
|
||||||
uint8_t *Out, size_t MaxOutSize) {
|
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.
|
} // namespace fuzzer.
|
||||||
|
@@ -42,6 +42,26 @@ int main(int argc, char **argv) {
|
|||||||
*/
|
*/
|
||||||
int FuzzerDriver(int argc, char **argv, UserCallback Callback);
|
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.
|
/** An abstract class that allows to use user-supplied mutators with libFuzzer.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@@ -50,6 +70,7 @@ Usage:
|
|||||||
#include "FuzzerInterface.h"
|
#include "FuzzerInterface.h"
|
||||||
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
||||||
public:
|
public:
|
||||||
|
MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
|
||||||
// Must define the target function.
|
// Must define the target function.
|
||||||
void TargetFunction(...) { ... }
|
void TargetFunction(...) { ... }
|
||||||
// Optionally define the mutator.
|
// Optionally define the mutator.
|
||||||
@@ -66,6 +87,8 @@ int main(int argc, char **argv) {
|
|||||||
*/
|
*/
|
||||||
class UserSuppliedFuzzer {
|
class UserSuppliedFuzzer {
|
||||||
public:
|
public:
|
||||||
|
UserSuppliedFuzzer(); // Deprecated, don't use.
|
||||||
|
UserSuppliedFuzzer(FuzzerRandomBase *Rand);
|
||||||
/// Executes the target function on 'Size' bytes of 'Data'.
|
/// Executes the target function on 'Size' bytes of 'Data'.
|
||||||
virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0;
|
virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0;
|
||||||
/// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes,
|
/// 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) {
|
uint8_t *Out, size_t MaxOutSize) {
|
||||||
return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
|
return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
|
||||||
}
|
}
|
||||||
virtual ~UserSuppliedFuzzer() {}
|
virtual ~UserSuppliedFuzzer();
|
||||||
|
|
||||||
|
FuzzerRandomBase &GetRand() { return *Rand; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// These can be called internally by Mutate and CrossOver.
|
/// 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,
|
size_t BasicCrossOver(const uint8_t *Data1, size_t Size1,
|
||||||
const uint8_t *Data2, size_t Size2,
|
const uint8_t *Data2, size_t Size2,
|
||||||
uint8_t *Out, size_t MaxOutSize);
|
uint8_t *Out, size_t MaxOutSize);
|
||||||
|
private:
|
||||||
|
bool OwnRand = false;
|
||||||
|
FuzzerRandomBase *Rand;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Runs the fuzzing with the UserSuppliedFuzzer.
|
/// Runs the fuzzing with the UserSuppliedFuzzer.
|
||||||
|
@@ -33,10 +33,12 @@ void CopyFileToErr(const std::string &Path);
|
|||||||
std::string DirPlusFile(const std::string &DirPath,
|
std::string DirPlusFile(const std::string &DirPath,
|
||||||
const std::string &FileName);
|
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 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 Printf(const char *Fmt, ...);
|
||||||
void Print(const Unit &U, const char *PrintAfter = "");
|
void Print(const Unit &U, const char *PrintAfter = "");
|
||||||
@@ -155,7 +157,8 @@ class Fuzzer {
|
|||||||
|
|
||||||
class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
|
class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
|
||||||
public:
|
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) {
|
virtual void TargetFunction(const uint8_t *Data, size_t Size) {
|
||||||
return Callback(Data, Size);
|
return Callback(Data, Size);
|
||||||
}
|
}
|
||||||
|
@@ -113,14 +113,14 @@ void Fuzzer::RereadOutputCorpus() {
|
|||||||
|
|
||||||
void Fuzzer::ShuffleAndMinimize() {
|
void Fuzzer::ShuffleAndMinimize() {
|
||||||
size_t MaxCov = 0;
|
size_t MaxCov = 0;
|
||||||
bool PreferSmall =
|
bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
|
||||||
(Options.PreferSmallDuringInitialShuffle == 1 ||
|
(Options.PreferSmallDuringInitialShuffle == -1 &&
|
||||||
(Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2));
|
USF.GetRand().RandBool()));
|
||||||
if (Options.Verbosity)
|
if (Options.Verbosity)
|
||||||
Printf("PreferSmall: %d\n", PreferSmall);
|
Printf("PreferSmall: %d\n", PreferSmall);
|
||||||
PrintStats("READ ", 0);
|
PrintStats("READ ", 0);
|
||||||
std::vector<Unit> NewCorpus;
|
std::vector<Unit> NewCorpus;
|
||||||
std::random_shuffle(Corpus.begin(), Corpus.end());
|
std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand());
|
||||||
if (PreferSmall)
|
if (PreferSmall)
|
||||||
std::stable_sort(
|
std::stable_sort(
|
||||||
Corpus.begin(), Corpus.end(),
|
Corpus.begin(), Corpus.end(),
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
|
|
||||||
namespace fuzzer {
|
namespace fuzzer {
|
||||||
|
|
||||||
static char FlipRandomBit(char X) {
|
static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
|
||||||
int Bit = rand() % 8;
|
int Bit = Rand(8);
|
||||||
char Mask = 1 << Bit;
|
char Mask = 1 << Bit;
|
||||||
char R;
|
char R;
|
||||||
if (X & (1 << Bit))
|
if (X & (1 << Bit))
|
||||||
@@ -27,24 +27,25 @@ static char FlipRandomBit(char X) {
|
|||||||
return R;
|
return R;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char RandCh() {
|
static char RandCh(FuzzerRandomBase &Rand) {
|
||||||
if (rand() % 2) return rand();
|
if (Rand.RandBool()) return Rand(256);
|
||||||
const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
|
const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
|
||||||
return Special[rand() % (sizeof(Special) - 1)];
|
return Special[Rand(sizeof(Special) - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutates Data in place, returns new size.
|
// 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(MaxSize > 0);
|
||||||
assert(Size <= MaxSize);
|
assert(Size <= MaxSize);
|
||||||
if (Size == 0) {
|
if (Size == 0) {
|
||||||
for (size_t i = 0; i < MaxSize; i++)
|
for (size_t i = 0; i < MaxSize; i++)
|
||||||
Data[i] = RandCh();
|
Data[i] = RandCh(Rand);
|
||||||
return MaxSize;
|
return MaxSize;
|
||||||
}
|
}
|
||||||
assert(Size > 0);
|
assert(Size > 0);
|
||||||
size_t Idx = rand() % Size;
|
size_t Idx = Rand(Size);
|
||||||
switch (rand() % 3) {
|
switch (Rand(3)) {
|
||||||
case 0:
|
case 0:
|
||||||
if (Size > 1) {
|
if (Size > 1) {
|
||||||
// Erase Data[Idx].
|
// Erase Data[Idx].
|
||||||
@@ -56,12 +57,12 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
|||||||
if (Size < MaxSize) {
|
if (Size < MaxSize) {
|
||||||
// Insert new value at Data[Idx].
|
// Insert new value at Data[Idx].
|
||||||
memmove(Data + Idx + 1, Data + Idx, Size - Idx);
|
memmove(Data + Idx + 1, Data + Idx, Size - Idx);
|
||||||
Data[Idx] = RandCh();
|
Data[Idx] = RandCh(Rand);
|
||||||
}
|
}
|
||||||
Data[Idx] = RandCh();
|
Data[Idx] = RandCh(Rand);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
Data[Idx] = FlipRandomBit(Data[Idx]);
|
Data[Idx] = FlipRandomBit(Data[Idx], Rand);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(Size > 0);
|
assert(Size > 0);
|
||||||
|
@@ -191,9 +191,9 @@ class TraceState {
|
|||||||
Mutations.clear();
|
Mutations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t StopTraceRecording() {
|
size_t StopTraceRecording(FuzzerRandomBase &Rand) {
|
||||||
RecordingTraces = false;
|
RecordingTraces = false;
|
||||||
std::random_shuffle(Mutations.begin(), Mutations.end());
|
std::random_shuffle(Mutations.begin(), Mutations.end(), Rand);
|
||||||
return Mutations.size();
|
return Mutations.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ void Fuzzer::StartTraceRecording() {
|
|||||||
|
|
||||||
size_t Fuzzer::StopTraceRecording() {
|
size_t Fuzzer::StopTraceRecording() {
|
||||||
if (!TS) return 0;
|
if (!TS) return 0;
|
||||||
return TS->StopTraceRecording();
|
return TS->StopTraceRecording(USF.GetRand());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) {
|
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) {
|
TEST(Fuzzer, CrossOver) {
|
||||||
using namespace fuzzer;
|
using namespace fuzzer;
|
||||||
|
FuzzerRandomLibc Rand(0);
|
||||||
Unit A({0, 1, 2}), B({5, 6, 7});
|
Unit A({0, 1, 2}), B({5, 6, 7});
|
||||||
Unit C;
|
Unit C;
|
||||||
Unit Expected[] = {
|
Unit Expected[] = {
|
||||||
@@ -53,7 +54,7 @@ TEST(Fuzzer, CrossOver) {
|
|||||||
for (int Iter = 0; Iter < 3000; Iter++) {
|
for (int Iter = 0; Iter < 3000; Iter++) {
|
||||||
C.resize(Len);
|
C.resize(Len);
|
||||||
size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(),
|
size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(),
|
||||||
C.data(), C.size());
|
C.data(), C.size(), Rand);
|
||||||
C.resize(NewSize);
|
C.resize(NewSize);
|
||||||
FoundUnits.insert(C);
|
FoundUnits.insert(C);
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@ static const uint64_t kMagic = 8860221463604ULL;
|
|||||||
|
|
||||||
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
||||||
public:
|
public:
|
||||||
|
MyFuzzer(fuzzer::FuzzerRandomBase *Rand)
|
||||||
|
: fuzzer::UserSuppliedFuzzer(Rand) {}
|
||||||
void TargetFunction(const uint8_t *Data, size_t Size) {
|
void TargetFunction(const uint8_t *Data, size_t Size) {
|
||||||
if (Size <= 10) return;
|
if (Size <= 10) return;
|
||||||
if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
|
if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
|
||||||
@@ -42,6 +44,7 @@ class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
MyFuzzer F;
|
fuzzer::FuzzerRandomLibc Rand(0);
|
||||||
|
MyFuzzer F(&Rand);
|
||||||
fuzzer::FuzzerDriver(argc, argv, F);
|
fuzzer::FuzzerDriver(argc, argv, F);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user