forked from OSchip/llvm-project
parent
381fc0ee3c
commit
f67357c671
|
@ -19,7 +19,6 @@
|
|||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
@ -360,8 +359,6 @@ private:
|
|||
std::vector<Mutator> DefaultMutators;
|
||||
};
|
||||
|
||||
class CoverageController;
|
||||
|
||||
class Fuzzer {
|
||||
public:
|
||||
|
||||
|
@ -488,6 +485,11 @@ private:
|
|||
void DumpCurrentUnit(const char *Prefix);
|
||||
void DeathCallback();
|
||||
|
||||
void ResetEdgeCoverage();
|
||||
void ResetCounters();
|
||||
void PrepareCounters(Fuzzer::Coverage *C);
|
||||
bool RecordMaxCoverage(Fuzzer::Coverage *C);
|
||||
|
||||
void LazyAllocateCurrentUnitData();
|
||||
uint8_t *CurrentUnitData = nullptr;
|
||||
std::atomic<size_t> CurrentUnitSize;
|
||||
|
@ -513,7 +515,10 @@ private:
|
|||
|
||||
// Maximum recorded coverage.
|
||||
Coverage MaxCoverage;
|
||||
std::unique_ptr<CoverageController> CController;
|
||||
|
||||
// For -print_new_cov_pcs
|
||||
uintptr_t* PcBuffer = nullptr;
|
||||
size_t PcBufferLen = 0;
|
||||
|
||||
// Need to know our own thread.
|
||||
static thread_local bool IsMyThread;
|
||||
|
|
|
@ -53,102 +53,82 @@ static void MissingExternalApiFunction(const char *FnName) {
|
|||
// Only one Fuzzer per process.
|
||||
static Fuzzer *F;
|
||||
|
||||
// Only one CoverageController per process should be created.
|
||||
class CoverageController {
|
||||
public:
|
||||
explicit CoverageController(const FuzzingOptions &Options)
|
||||
: Options(Options) {
|
||||
if (Options.PrintNewCovPcs) {
|
||||
PcBufferLen = 1 << 24;
|
||||
PcBuffer = new uintptr_t[PcBufferLen];
|
||||
EF->__sanitizer_set_coverage_pc_buffer(PcBuffer, PcBufferLen);
|
||||
}
|
||||
void Fuzzer::ResetEdgeCoverage() {
|
||||
CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage);
|
||||
EF->__sanitizer_reset_coverage();
|
||||
}
|
||||
|
||||
void Fuzzer::ResetCounters() {
|
||||
if (Options.UseCounters) {
|
||||
EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) {
|
||||
if (Options.UseCounters) {
|
||||
size_t NumCounters = EF->__sanitizer_get_number_of_counters();
|
||||
C->CounterBitmap.resize(NumCounters);
|
||||
}
|
||||
}
|
||||
|
||||
// Records data to a maximum coverage tracker. Returns true if additional
|
||||
// coverage was discovered.
|
||||
bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
|
||||
bool Res = false;
|
||||
|
||||
uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
|
||||
if (NewBlockCoverage > C->BlockCoverage) {
|
||||
Res = true;
|
||||
C->BlockCoverage = NewBlockCoverage;
|
||||
}
|
||||
|
||||
uintptr_t* pc_buffer() const { return PcBuffer; }
|
||||
|
||||
void Reset() {
|
||||
CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage);
|
||||
EF->__sanitizer_reset_coverage();
|
||||
}
|
||||
|
||||
void ResetCounters() {
|
||||
if (Options.UseCounters) {
|
||||
EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Prepare(Fuzzer::Coverage *C) {
|
||||
if (Options.UseCounters) {
|
||||
size_t NumCounters = EF->__sanitizer_get_number_of_counters();
|
||||
C->CounterBitmap.resize(NumCounters);
|
||||
}
|
||||
}
|
||||
|
||||
// Records data to a maximum coverage tracker. Returns true if additional
|
||||
// coverage was discovered.
|
||||
bool RecordMax(Fuzzer::Coverage *C) {
|
||||
bool Res = false;
|
||||
|
||||
uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
|
||||
if (NewBlockCoverage > C->BlockCoverage) {
|
||||
if (Options.UseIndirCalls &&
|
||||
EF->__sanitizer_get_total_unique_caller_callee_pairs) {
|
||||
uint64_t NewCallerCalleeCoverage =
|
||||
EF->__sanitizer_get_total_unique_caller_callee_pairs();
|
||||
if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) {
|
||||
Res = true;
|
||||
C->BlockCoverage = NewBlockCoverage;
|
||||
C->CallerCalleeCoverage = NewCallerCalleeCoverage;
|
||||
}
|
||||
|
||||
if (Options.UseIndirCalls &&
|
||||
EF->__sanitizer_get_total_unique_caller_callee_pairs) {
|
||||
uint64_t NewCallerCalleeCoverage =
|
||||
EF->__sanitizer_get_total_unique_caller_callee_pairs();
|
||||
if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) {
|
||||
Res = true;
|
||||
C->CallerCalleeCoverage = NewCallerCalleeCoverage;
|
||||
}
|
||||
}
|
||||
|
||||
if (Options.UseCounters) {
|
||||
uint64_t CounterDelta =
|
||||
EF->__sanitizer_update_counter_bitset_and_clear_counters(
|
||||
C->CounterBitmap.data());
|
||||
if (CounterDelta > 0) {
|
||||
Res = true;
|
||||
C->CounterBitmapBits += CounterDelta;
|
||||
}
|
||||
}
|
||||
|
||||
size_t NewPCMapBits = PCMapMergeFromCurrent(C->PCMap);
|
||||
if (NewPCMapBits > C->PCMapBits) {
|
||||
Res = true;
|
||||
C->PCMapBits = NewPCMapBits;
|
||||
}
|
||||
|
||||
size_t NewVPMapBits = VPMapMergeFromCurrent(C->VPMap);
|
||||
if (NewVPMapBits > C->VPMapBits) {
|
||||
Res = true;
|
||||
C->VPMapBits = NewVPMapBits;
|
||||
}
|
||||
|
||||
if (EF->__sanitizer_get_coverage_pc_buffer_pos) {
|
||||
uint64_t NewPcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
|
||||
if (NewPcBufferPos > C->PcBufferPos) {
|
||||
Res = true;
|
||||
C->PcBufferPos = NewPcBufferPos;
|
||||
}
|
||||
|
||||
if (PcBufferLen && NewPcBufferPos >= PcBufferLen) {
|
||||
Printf("ERROR: PC buffer overflow\n");
|
||||
_Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
private:
|
||||
const FuzzingOptions Options;
|
||||
uintptr_t* PcBuffer = nullptr;
|
||||
size_t PcBufferLen = 0;
|
||||
};
|
||||
if (Options.UseCounters) {
|
||||
uint64_t CounterDelta =
|
||||
EF->__sanitizer_update_counter_bitset_and_clear_counters(
|
||||
C->CounterBitmap.data());
|
||||
if (CounterDelta > 0) {
|
||||
Res = true;
|
||||
C->CounterBitmapBits += CounterDelta;
|
||||
}
|
||||
}
|
||||
|
||||
size_t NewPCMapBits = PCMapMergeFromCurrent(C->PCMap);
|
||||
if (NewPCMapBits > C->PCMapBits) {
|
||||
Res = true;
|
||||
C->PCMapBits = NewPCMapBits;
|
||||
}
|
||||
|
||||
size_t NewVPMapBits = VPMapMergeFromCurrent(C->VPMap);
|
||||
if (NewVPMapBits > C->VPMapBits) {
|
||||
Res = true;
|
||||
C->VPMapBits = NewVPMapBits;
|
||||
}
|
||||
|
||||
if (EF->__sanitizer_get_coverage_pc_buffer_pos) {
|
||||
uint64_t NewPcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
|
||||
if (NewPcBufferPos > C->PcBufferPos) {
|
||||
Res = true;
|
||||
C->PcBufferPos = NewPcBufferPos;
|
||||
}
|
||||
|
||||
if (PcBufferLen && NewPcBufferPos >= PcBufferLen) {
|
||||
Printf("ERROR: PC buffer overflow\n");
|
||||
_Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
// Leak detection is expensive, so we first check if there were more mallocs
|
||||
// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
|
||||
|
@ -173,8 +153,7 @@ void FreeHook(const volatile void *ptr) {
|
|||
}
|
||||
|
||||
Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
|
||||
: CB(CB), MD(MD), Options(Options),
|
||||
CController(new CoverageController(Options)) {
|
||||
: CB(CB), MD(MD), Options(Options) {
|
||||
SetDeathCallback();
|
||||
InitializeTraceState();
|
||||
assert(!F);
|
||||
|
@ -183,6 +162,12 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
|
|||
IsMyThread = true;
|
||||
if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
|
||||
EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
|
||||
|
||||
if (Options.PrintNewCovPcs) {
|
||||
PcBufferLen = 1 << 24;
|
||||
PcBuffer = new uintptr_t[PcBufferLen];
|
||||
EF->__sanitizer_set_coverage_pc_buffer(PcBuffer, PcBufferLen);
|
||||
}
|
||||
}
|
||||
|
||||
Fuzzer::~Fuzzer() { }
|
||||
|
@ -457,10 +442,9 @@ void Fuzzer::ShuffleAndMinimize() {
|
|||
|
||||
bool Fuzzer::UpdateMaxCoverage() {
|
||||
uintptr_t PrevPcBufferPos = MaxCoverage.PcBufferPos;
|
||||
bool Res = CController->RecordMax(&MaxCoverage);
|
||||
bool Res = RecordMaxCoverage(&MaxCoverage);
|
||||
|
||||
if (Options.PrintNewCovPcs && PrevPcBufferPos != MaxCoverage.PcBufferPos) {
|
||||
uintptr_t* PcBuffer = CController->pc_buffer();
|
||||
for (size_t I = PrevPcBufferPos; I < MaxCoverage.PcBufferPos; ++I) {
|
||||
Printf("%p\n", PcBuffer[I]);
|
||||
}
|
||||
|
@ -473,7 +457,7 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
|
|||
TotalNumberOfRuns++;
|
||||
|
||||
// TODO(aizatsky): this Reset call seems to be not needed.
|
||||
CController->ResetCounters();
|
||||
ResetCounters();
|
||||
ExecuteCallback(Data, Size);
|
||||
bool Res = UpdateMaxCoverage();
|
||||
|
||||
|
@ -511,18 +495,19 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
|
|||
UnitStartTime = system_clock::now();
|
||||
// We copy the contents of Unit into a separate heap buffer
|
||||
// so that we reliably find buffer overflows in it.
|
||||
std::unique_ptr<uint8_t[]> DataCopy(new uint8_t[Size]);
|
||||
memcpy(DataCopy.get(), Data, Size);
|
||||
uint8_t *DataCopy = new uint8_t[Size];
|
||||
memcpy(DataCopy, Data, Size);
|
||||
if (CurrentUnitData && CurrentUnitData != Data)
|
||||
memcpy(CurrentUnitData, Data, Size);
|
||||
AssignTaintLabels(DataCopy.get(), Size);
|
||||
AssignTaintLabels(DataCopy, Size);
|
||||
CurrentUnitSize = Size;
|
||||
AllocTracer.Start();
|
||||
int Res = CB(DataCopy.get(), Size);
|
||||
int Res = CB(DataCopy, Size);
|
||||
(void)Res;
|
||||
HasMoreMallocsThanFrees = AllocTracer.Stop();
|
||||
CurrentUnitSize = 0;
|
||||
assert(Res == 0);
|
||||
delete[] DataCopy;
|
||||
}
|
||||
|
||||
std::string Fuzzer::Coverage::DebugString() const {
|
||||
|
@ -728,9 +713,9 @@ size_t Fuzzer::ChooseUnitIdxToMutate() {
|
|||
}
|
||||
|
||||
void Fuzzer::ResetCoverage() {
|
||||
CController->Reset();
|
||||
ResetEdgeCoverage();
|
||||
MaxCoverage.Reset();
|
||||
CController->Prepare(&MaxCoverage);
|
||||
PrepareCounters(&MaxCoverage);
|
||||
}
|
||||
|
||||
// Experimental search heuristic: drilling.
|
||||
|
|
Loading…
Reference in New Issue