// 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;
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;
}
int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
- SimpleUserSuppliedFuzzer SUSF(Callback);
+ FuzzerRandomLibc Rand(0);
+ SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
return FuzzerDriver(argc, argv, SUSF);
}
Seed = time(0) * 10000 + getpid();
if (Flags.verbosity)
Printf("Seed: %u\n", Seed);
- srand(Seed);
+ USF.GetRand().ResetSeed(Seed);
// Timer
if (Flags.timeout > 0)
#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.
*/
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:
#include "FuzzerInterface.h"
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
public:
+ MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
// Must define the target function.
void TargetFunction(...) { ... }
// Optionally define the mutator.
*/
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,
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.
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.
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 = "");
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);
}
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(),
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))
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].
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);
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();
}
size_t Fuzzer::StopTraceRecording() {
if (!TS) return 0;
- return TS->StopTraceRecording();
+ return TS->StopTraceRecording(USF.GetRand());
}
void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) {
TEST(Fuzzer, CrossOver) {
using namespace fuzzer;
+ FuzzerRandomLibc Rand(0);
Unit A({0, 1, 2}), B({5, 6, 7});
Unit C;
Unit Expected[] = {
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);
}
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;
};
int main(int argc, char **argv) {
- MyFuzzer F;
+ fuzzer::FuzzerRandomLibc Rand(0);
+ MyFuzzer F(&Rand);
fuzzer::FuzzerDriver(argc, argv, F);
}