mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-18 11:24:01 +00:00
[lib/Fuzzer] extend the fuzzer interface to allow user-supplied mutators
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238059 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -2,8 +2,9 @@ set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}")
|
|||||||
# Disable the coverage and sanitizer instrumentation for the fuzzer itself.
|
# Disable the coverage and sanitizer instrumentation for the fuzzer itself.
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all")
|
set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all")
|
||||||
if( LLVM_USE_SANITIZE_COVERAGE )
|
if( LLVM_USE_SANITIZE_COVERAGE )
|
||||||
add_library(LLVMFuzzerNoMain OBJECT
|
add_library(LLVMFuzzerNoMainObjects OBJECT
|
||||||
FuzzerCrossOver.cpp
|
FuzzerCrossOver.cpp
|
||||||
|
FuzzerInterface.cpp
|
||||||
FuzzerTraceState.cpp
|
FuzzerTraceState.cpp
|
||||||
FuzzerDriver.cpp
|
FuzzerDriver.cpp
|
||||||
FuzzerIO.cpp
|
FuzzerIO.cpp
|
||||||
@ -13,9 +14,12 @@ if( LLVM_USE_SANITIZE_COVERAGE )
|
|||||||
FuzzerSHA1.cpp
|
FuzzerSHA1.cpp
|
||||||
FuzzerUtil.cpp
|
FuzzerUtil.cpp
|
||||||
)
|
)
|
||||||
|
add_library(LLVMFuzzerNoMain STATIC
|
||||||
|
$<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
|
||||||
|
)
|
||||||
add_library(LLVMFuzzer STATIC
|
add_library(LLVMFuzzer STATIC
|
||||||
FuzzerMain.cpp
|
FuzzerMain.cpp
|
||||||
$<TARGET_OBJECTS:LLVMFuzzerNoMain>
|
$<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
|
||||||
)
|
)
|
||||||
|
|
||||||
if( LLVM_INCLUDE_TESTS )
|
if( LLVM_INCLUDE_TESTS )
|
||||||
|
@ -9,39 +9,42 @@
|
|||||||
// Cross over test inputs.
|
// Cross over test inputs.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "FuzzerInternal.h"
|
#include "FuzzerInternal.h"
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace fuzzer {
|
namespace fuzzer {
|
||||||
|
|
||||||
// Cross A and B, store the result (ap to MaxLen bytes) in U.
|
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
|
||||||
void CrossOver(const Unit &A, const Unit &B, Unit *U, size_t MaxLen) {
|
size_t CrossOver(const uint8_t *Data1, size_t Size1,
|
||||||
size_t Size = rand() % MaxLen + 1;
|
const uint8_t *Data2, size_t Size2,
|
||||||
U->clear();
|
uint8_t *Out, size_t MaxOutSize) {
|
||||||
const Unit *V = &A;
|
MaxOutSize = rand() % MaxOutSize + 1;
|
||||||
size_t PosA = 0;
|
size_t OutPos = 0;
|
||||||
size_t PosB = 0;
|
size_t Pos1 = 0;
|
||||||
size_t *Pos = &PosA;
|
size_t Pos2 = 0;
|
||||||
while (U->size() < Size && (PosA < A.size() || PosB < B.size())) {
|
size_t *InPos = &Pos1;
|
||||||
// Merge a part of V into U.
|
size_t InSize = Size1;
|
||||||
size_t SizeLeftU = Size - U->size();
|
const uint8_t *Data = Data1;
|
||||||
if (*Pos < V->size()) {
|
bool CurrentlyUsingFirstData = true;
|
||||||
size_t SizeLeftV = V->size() - *Pos;
|
while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) {
|
||||||
size_t MaxExtraSize = std::min(SizeLeftU, SizeLeftV);
|
// Merge a part of Data into Out.
|
||||||
|
size_t OutSizeLeft = MaxOutSize - OutPos;
|
||||||
|
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;
|
||||||
U->insert(U->end(), V->begin() + *Pos, V->begin() + *Pos + ExtraSize);
|
memcpy(Out + OutPos, Data + *InPos, ExtraSize);
|
||||||
(*Pos) += ExtraSize;
|
OutPos += ExtraSize;
|
||||||
}
|
(*InPos) += ExtraSize;
|
||||||
|
|
||||||
// Use the other Unit on the next iteration.
|
|
||||||
if (Pos == &PosA) {
|
|
||||||
Pos = &PosB;
|
|
||||||
V = &B;
|
|
||||||
} else {
|
|
||||||
Pos = &PosA;
|
|
||||||
V = &A;
|
|
||||||
}
|
}
|
||||||
|
// Use the other input data on the next iteration.
|
||||||
|
InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
|
||||||
|
InSize = CurrentlyUsingFirstData ? Size2 : Size1;
|
||||||
|
Data = CurrentlyUsingFirstData ? Data2 : Data1;
|
||||||
|
CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
|
||||||
}
|
}
|
||||||
|
return OutPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
@ -204,6 +204,11 @@ 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);
|
||||||
|
return FuzzerDriver(argc, argv, SUSF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) {
|
||||||
using namespace fuzzer;
|
using namespace fuzzer;
|
||||||
|
|
||||||
ProgName = argv[0];
|
ProgName = argv[0];
|
||||||
@ -244,7 +249,7 @@ int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
|
|||||||
if (Flags.sync_command)
|
if (Flags.sync_command)
|
||||||
Options.SyncCommand = Flags.sync_command;
|
Options.SyncCommand = Flags.sync_command;
|
||||||
Options.SyncTimeout = Flags.sync_timeout;
|
Options.SyncTimeout = Flags.sync_timeout;
|
||||||
Fuzzer F(Callback, Options);
|
Fuzzer F(USF, Options);
|
||||||
|
|
||||||
unsigned seed = Flags.seed;
|
unsigned seed = Flags.seed;
|
||||||
// Initialize seed.
|
// Initialize seed.
|
||||||
|
27
lib/Fuzzer/FuzzerInterface.cpp
Normal file
27
lib/Fuzzer/FuzzerInterface.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//===- FuzzerInterface.cpp - Mutate a test input --------------------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Parts of public interface for libFuzzer.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
#include "FuzzerInterface.h"
|
||||||
|
#include "FuzzerInternal.h"
|
||||||
|
|
||||||
|
namespace fuzzer {
|
||||||
|
size_t UserSuppliedFuzzer::BasicMutate(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize) {
|
||||||
|
return ::fuzzer::Mutate(Data, Size, MaxSize);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fuzzer.
|
@ -9,6 +9,10 @@
|
|||||||
// Define the interface between the Fuzzer and the library being tested.
|
// Define the interface between the Fuzzer and the library being tested.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// WARNING: keep the interface free of STL or any other header-based C++ lib,
|
||||||
|
// to avoid bad interactions between the code used in the fuzzer and
|
||||||
|
// the code used in the target function.
|
||||||
|
|
||||||
#ifndef LLVM_FUZZER_INTERFACE_H
|
#ifndef LLVM_FUZZER_INTERFACE_H
|
||||||
#define LLVM_FUZZER_INTERFACE_H
|
#define LLVM_FUZZER_INTERFACE_H
|
||||||
|
|
||||||
@ -17,9 +21,69 @@
|
|||||||
|
|
||||||
namespace fuzzer {
|
namespace fuzzer {
|
||||||
|
|
||||||
typedef void (*UserCallback)(const uint8_t *data, size_t size);
|
// Simple C-like interface with a single user-supplied callback.
|
||||||
|
/* Usage: ---------------------------------------------------------------------
|
||||||
|
#include "FuzzerInterface.h"
|
||||||
|
|
||||||
|
void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
DoStuffWithData(Data, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement your own main() or use the one from FuzzerMain.cpp.
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
InitializeMeIfNeeded();
|
||||||
|
return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput);
|
||||||
|
}
|
||||||
|
----------------------------------------------------------------------------- */
|
||||||
|
typedef void (*UserCallback)(const uint8_t *Data, size_t Size);
|
||||||
int FuzzerDriver(int argc, char **argv, UserCallback Callback);
|
int FuzzerDriver(int argc, char **argv, UserCallback Callback);
|
||||||
|
|
||||||
|
// An abstract class that allows to use user-supplied mutators with libFuzzer.
|
||||||
|
/* Usage: ---------------------------------------------------------------------
|
||||||
|
#include "FuzzerInterface.h"
|
||||||
|
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
||||||
|
public:
|
||||||
|
// Must define the target function.
|
||||||
|
void TargetFunction(...) { ... }
|
||||||
|
// Optionally define the mutator.
|
||||||
|
size_t Mutate(...) { ... }
|
||||||
|
// Optionally define the CrossOver method.
|
||||||
|
size_t CrossOver(...) { ... }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
MyFuzzer F;
|
||||||
|
fuzzer::FuzzerDriver(argc, argv, F);
|
||||||
|
}
|
||||||
|
----------------------------------------------------------------------------- */
|
||||||
|
class UserSuppliedFuzzer {
|
||||||
|
public:
|
||||||
|
// 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,
|
||||||
|
// returns the new size of the data.
|
||||||
|
virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||||
|
return BasicMutate(Data, Size, MaxSize);
|
||||||
|
}
|
||||||
|
// Crosses 'Data1' and 'Data2', writes up to 'MaxOutSize' bytes into Out,
|
||||||
|
// returns the number of bytes written.
|
||||||
|
virtual size_t CrossOver(const uint8_t *Data1, size_t Size1,
|
||||||
|
const uint8_t *Data2, size_t Size2,
|
||||||
|
uint8_t *Out, size_t MaxOutSize) {
|
||||||
|
return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
|
||||||
|
}
|
||||||
|
virtual ~UserSuppliedFuzzer() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// These can be called internally by Mutate and CrossOver.
|
||||||
|
size_t BasicMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t BasicCrossOver(const uint8_t *Data1, size_t Size1,
|
||||||
|
const uint8_t *Data2, size_t Size2,
|
||||||
|
uint8_t *Out, size_t MaxOutSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF);
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
|
||||||
#endif // LLVM_FUZZER_INTERFACE_H
|
#endif // LLVM_FUZZER_INTERFACE_H
|
||||||
|
@ -33,9 +33,10 @@ 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);
|
||||||
|
|
||||||
void Mutate(Unit *U, size_t MaxLen);
|
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
|
||||||
void CrossOver(const Unit &A, const Unit &B, Unit *U, size_t MaxLen);
|
size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
|
||||||
|
size_t Size2, uint8_t *Out, size_t MaxOutSize);
|
||||||
|
|
||||||
void Print(const Unit &U, const char *PrintAfter = "");
|
void Print(const Unit &U, const char *PrintAfter = "");
|
||||||
void PrintASCII(const Unit &U, const char *PrintAfter = "");
|
void PrintASCII(const Unit &U, const char *PrintAfter = "");
|
||||||
@ -72,7 +73,7 @@ class Fuzzer {
|
|||||||
std::string SyncCommand;
|
std::string SyncCommand;
|
||||||
std::vector<std::string> Tokens;
|
std::vector<std::string> Tokens;
|
||||||
};
|
};
|
||||||
Fuzzer(UserCallback Callback, FuzzingOptions Options);
|
Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options);
|
||||||
void AddToCorpus(const Unit &U) { Corpus.push_back(U); }
|
void AddToCorpus(const Unit &U) { Corpus.push_back(U); }
|
||||||
void Loop(size_t NumIterations);
|
void Loop(size_t NumIterations);
|
||||||
void ShuffleAndMinimize();
|
void ShuffleAndMinimize();
|
||||||
@ -144,7 +145,7 @@ class Fuzzer {
|
|||||||
return Res;
|
return Res;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserCallback Callback;
|
UserSuppliedFuzzer &USF;
|
||||||
FuzzingOptions Options;
|
FuzzingOptions Options;
|
||||||
system_clock::time_point ProcessStartTime = system_clock::now();
|
system_clock::time_point ProcessStartTime = system_clock::now();
|
||||||
system_clock::time_point LastExternalSync = system_clock::now();
|
system_clock::time_point LastExternalSync = system_clock::now();
|
||||||
@ -153,4 +154,15 @@ class Fuzzer {
|
|||||||
long EpochOfLastReadOfOutputCorpus = 0;
|
long EpochOfLastReadOfOutputCorpus = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
|
||||||
|
public:
|
||||||
|
SimpleUserSuppliedFuzzer(UserCallback Callback) : Callback(Callback) {}
|
||||||
|
virtual void TargetFunction(const uint8_t *Data, size_t Size) {
|
||||||
|
return Callback(Data, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UserCallback Callback;
|
||||||
|
};
|
||||||
|
|
||||||
}; // namespace fuzzer
|
}; // namespace fuzzer
|
||||||
|
@ -19,8 +19,8 @@ namespace fuzzer {
|
|||||||
// Only one Fuzzer per process.
|
// Only one Fuzzer per process.
|
||||||
static Fuzzer *F;
|
static Fuzzer *F;
|
||||||
|
|
||||||
Fuzzer::Fuzzer(UserCallback Callback, FuzzingOptions Options)
|
Fuzzer::Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options)
|
||||||
: Callback(Callback), Options(Options) {
|
: USF(USF), Options(Options) {
|
||||||
SetDeathCallback();
|
SetDeathCallback();
|
||||||
InitializeTraceState();
|
InitializeTraceState();
|
||||||
assert(!F);
|
assert(!F);
|
||||||
@ -207,10 +207,10 @@ Unit Fuzzer::SubstituteTokens(const Unit &U) const {
|
|||||||
|
|
||||||
void Fuzzer::ExecuteCallback(const Unit &U) {
|
void Fuzzer::ExecuteCallback(const Unit &U) {
|
||||||
if (Options.Tokens.empty()) {
|
if (Options.Tokens.empty()) {
|
||||||
Callback(U.data(), U.size());
|
USF.TargetFunction(U.data(), U.size());
|
||||||
} else {
|
} else {
|
||||||
auto T = SubstituteTokens(U);
|
auto T = SubstituteTokens(U);
|
||||||
Callback(T.data(), T.size());
|
USF.TargetFunction(T.data(), T.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +321,11 @@ void Fuzzer::ReportNewCoverage(size_t NewCoverage, const Unit &U) {
|
|||||||
void Fuzzer::MutateAndTestOne(Unit *U) {
|
void Fuzzer::MutateAndTestOne(Unit *U) {
|
||||||
for (int i = 0; i < Options.MutateDepth; i++) {
|
for (int i = 0; i < Options.MutateDepth; i++) {
|
||||||
StartTraceRecording();
|
StartTraceRecording();
|
||||||
Mutate(U, Options.MaxLen);
|
size_t Size = U->size();
|
||||||
|
U->resize(Options.MaxLen);
|
||||||
|
size_t NewSize = USF.Mutate(U->data(), Size, U->size());
|
||||||
|
assert(NewSize > 0 && NewSize <= Options.MaxLen);
|
||||||
|
U->resize(NewSize);
|
||||||
RunOneAndUpdateCorpus(*U);
|
RunOneAndUpdateCorpus(*U);
|
||||||
size_t NumTraceBasedMutations = StopTraceRecording();
|
size_t NumTraceBasedMutations = StopTraceRecording();
|
||||||
for (size_t j = 0; j < NumTraceBasedMutations; j++) {
|
for (size_t j = 0; j < NumTraceBasedMutations; j++) {
|
||||||
@ -344,8 +348,12 @@ void Fuzzer::Loop(size_t NumIterations) {
|
|||||||
// Now, cross with others.
|
// Now, cross with others.
|
||||||
if (Options.DoCrossOver) {
|
if (Options.DoCrossOver) {
|
||||||
for (size_t J2 = 0; J2 < Corpus.size(); J2++) {
|
for (size_t J2 = 0; J2 < Corpus.size(); J2++) {
|
||||||
CurrentUnit.clear();
|
CurrentUnit.resize(Options.MaxLen);
|
||||||
CrossOver(Corpus[J1], Corpus[J2], &CurrentUnit, Options.MaxLen);
|
size_t NewSize = USF.CrossOver(
|
||||||
|
Corpus[J1].data(), Corpus[J1].size(), Corpus[J2].data(),
|
||||||
|
Corpus[J2].size(), CurrentUnit.data(), CurrentUnit.size());
|
||||||
|
assert(NewSize > 0 && NewSize <= Options.MaxLen);
|
||||||
|
CurrentUnit.resize(NewSize);
|
||||||
MutateAndTestOne(&CurrentUnit);
|
MutateAndTestOne(&CurrentUnit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
// Mutate a test input.
|
// Mutate a test input.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "FuzzerInternal.h"
|
#include "FuzzerInternal.h"
|
||||||
|
|
||||||
namespace fuzzer {
|
namespace fuzzer {
|
||||||
@ -31,40 +33,39 @@ static char RandCh() {
|
|||||||
return Special[rand() % (sizeof(Special) - 1)];
|
return Special[rand() % (sizeof(Special) - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutate U in place.
|
// Mutates Data in place, returns new size.
|
||||||
void Mutate(Unit *U, size_t MaxLen) {
|
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||||
assert(MaxLen > 0);
|
assert(MaxSize > 0);
|
||||||
assert(U->size() <= MaxLen);
|
assert(Size <= MaxSize);
|
||||||
if (U->empty()) {
|
if (Size == 0) {
|
||||||
for (size_t i = 0; i < MaxLen; i++)
|
for (size_t i = 0; i < MaxSize; i++)
|
||||||
U->push_back(RandCh());
|
Data[i] = RandCh();
|
||||||
return;
|
return MaxSize;
|
||||||
}
|
}
|
||||||
assert(!U->empty());
|
assert(Size > 0);
|
||||||
|
size_t Idx = rand() % Size;
|
||||||
switch (rand() % 3) {
|
switch (rand() % 3) {
|
||||||
case 0:
|
case 0:
|
||||||
if (U->size() > 1) {
|
if (Size > 1) {
|
||||||
U->erase(U->begin() + rand() % U->size());
|
// Erase Data[Idx].
|
||||||
break;
|
memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
|
||||||
|
Size = Size - 1;
|
||||||
}
|
}
|
||||||
[[clang::fallthrough]];
|
[[clang::fallthrough]];
|
||||||
case 1:
|
case 1:
|
||||||
if (U->size() < MaxLen) {
|
if (Size < MaxSize) {
|
||||||
U->insert(U->begin() + rand() % U->size(), RandCh());
|
// Insert new value at Data[Idx].
|
||||||
} else { // At MaxLen.
|
memmove(Data + Idx + 1, Data + Idx, Size - Idx);
|
||||||
uint8_t Ch = RandCh();
|
Data[Idx] = RandCh();
|
||||||
size_t Idx = rand() % U->size();
|
|
||||||
(*U)[Idx] = Ch;
|
|
||||||
}
|
}
|
||||||
|
Data[Idx] = RandCh();
|
||||||
break;
|
break;
|
||||||
default:
|
case 2:
|
||||||
{
|
Data[Idx] = FlipRandomBit(Data[Idx]);
|
||||||
size_t Idx = rand() % U->size();
|
|
||||||
(*U)[Idx] = FlipRandomBit((*U)[Idx]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(!U->empty());
|
assert(Size > 0);
|
||||||
|
return Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
@ -21,6 +21,10 @@ set(Tests
|
|||||||
${DFSanTests}
|
${DFSanTests}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(CustomMainTests
|
||||||
|
UserSuppliedFuzzerTest
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
set(TestBinaries)
|
set(TestBinaries)
|
||||||
|
|
||||||
@ -34,6 +38,17 @@ foreach(Test ${Tests})
|
|||||||
set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test})
|
set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
foreach(Test ${CustomMainTests})
|
||||||
|
add_executable(LLVMFuzzer-${Test}
|
||||||
|
${Test}.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(LLVMFuzzer-${Test}
|
||||||
|
LLVMFuzzerNoMain
|
||||||
|
)
|
||||||
|
set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
configure_lit_site_cfg(
|
configure_lit_site_cfg(
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
|
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
|
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
|
||||||
@ -49,7 +64,7 @@ include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include)
|
|||||||
|
|
||||||
add_executable(LLVMFuzzer-Unittest
|
add_executable(LLVMFuzzer-Unittest
|
||||||
FuzzerUnittest.cpp
|
FuzzerUnittest.cpp
|
||||||
$<TARGET_OBJECTS:LLVMFuzzerNoMain>
|
$<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(LLVMFuzzer-Unittest
|
target_link_libraries(LLVMFuzzer-Unittest
|
||||||
|
@ -51,7 +51,10 @@ TEST(Fuzzer, CrossOver) {
|
|||||||
for (size_t Len = 1; Len < 8; Len++) {
|
for (size_t Len = 1; Len < 8; Len++) {
|
||||||
std::set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
|
std::set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
|
||||||
for (int Iter = 0; Iter < 3000; Iter++) {
|
for (int Iter = 0; Iter < 3000; Iter++) {
|
||||||
CrossOver(A, B, &C, Len);
|
C.resize(Len);
|
||||||
|
size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(),
|
||||||
|
C.data(), C.size());
|
||||||
|
C.resize(NewSize);
|
||||||
FoundUnits.insert(C);
|
FoundUnits.insert(C);
|
||||||
}
|
}
|
||||||
for (const Unit &U : Expected)
|
for (const Unit &U : Expected)
|
||||||
|
47
lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp
Normal file
47
lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Simple test for a fuzzer.
|
||||||
|
// The fuzzer must find the string "Hi!" preceded by a magic value.
|
||||||
|
// Uses UserSuppliedFuzzer which ensures that the magic is present.
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "FuzzerInterface.h"
|
||||||
|
|
||||||
|
static const uint64_t kMagic = 8860221463604ULL;
|
||||||
|
|
||||||
|
class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
|
||||||
|
public:
|
||||||
|
void TargetFunction(const uint8_t *Data, size_t Size) {
|
||||||
|
if (Size <= 10) return;
|
||||||
|
if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
|
||||||
|
// It's hard to get here w/o advanced fuzzing techniques (e.g. cmp tracing).
|
||||||
|
// So, we simply 'fix' the data in the custom mutator.
|
||||||
|
if (Data[8] == 'H') {
|
||||||
|
if (Data[9] == 'i') {
|
||||||
|
if (Data[10] == '!') {
|
||||||
|
std::cout << "BINGO; Found the target, exiting\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Custom mutator.
|
||||||
|
virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||||
|
assert(MaxSize > sizeof(kMagic));
|
||||||
|
if (Size < sizeof(kMagic))
|
||||||
|
Size = sizeof(kMagic);
|
||||||
|
// "Fix" the data, then mutate.
|
||||||
|
memcpy(Data, &kMagic, std::min(MaxSize, sizeof(kMagic)));
|
||||||
|
return BasicMutate(Data + sizeof(kMagic), Size - sizeof(kMagic),
|
||||||
|
MaxSize - sizeof(kMagic));
|
||||||
|
}
|
||||||
|
// No need to redefine CrossOver() here.
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
MyFuzzer F;
|
||||||
|
fuzzer::FuzzerDriver(argc, argv, F);
|
||||||
|
}
|
@ -26,3 +26,5 @@ RUN: not ./LLVMFuzzer-DFSanMemcmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -tim
|
|||||||
|
|
||||||
RUN: not ./LLVMFuzzer-CxxTokensTest -seed=1 -timeout=15 -tokens=%S/../cxx_fuzzer_tokens.txt 2>&1 | FileCheck %s
|
RUN: not ./LLVMFuzzer-CxxTokensTest -seed=1 -timeout=15 -tokens=%S/../cxx_fuzzer_tokens.txt 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
RUN: not ./LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user