[libFuzzer] make CurrentUnit a POD object instead of vector to avoid extra allocations

llvm-svn: 257713
This commit is contained in:
Kostya Serebryany 2016-01-13 23:46:01 +00:00
parent 6b3faefff9
commit 98abb2c90a
4 changed files with 51 additions and 45 deletions

View File

@ -37,7 +37,9 @@ std::string DirPlusFile(const std::string &DirPath,
const std::string &FileName); const std::string &FileName);
void Printf(const char *Fmt, ...); void Printf(const char *Fmt, ...);
void Print(const Unit &U, const char *PrintAfter = ""); void PrintHexArray(const Unit &U, const char *PrintAfter = "");
void PrintHexArray(const uint8_t *Data, size_t Size,
const char *PrintAfter = "");
void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
void PrintASCII(const Unit &U, const char *PrintAfter = ""); void PrintASCII(const Unit &U, const char *PrintAfter = "");
std::string Hash(const Unit &U); std::string Hash(const Unit &U);
@ -140,7 +142,6 @@ class Fuzzer {
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
void PrintStats(const char *Where, const char *End = "\n"); void PrintStats(const char *Where, const char *End = "\n");
void PrintStatusForNewUnit(const Unit &U); void PrintStatusForNewUnit(const Unit &U);
void PrintUnitInASCII(const Unit &U, const char *PrintAfter = "");
void SyncCorpus(); void SyncCorpus();
@ -162,7 +163,9 @@ class Fuzzer {
void SetDeathCallback(); void SetDeathCallback();
static void StaticDeathCallback(); static void StaticDeathCallback();
void DeathCallback(); void DeathCallback();
Unit CurrentUnit;
uint8_t *CurrentUnitData;
size_t CurrentUnitSize;
size_t TotalNumberOfRuns = 0; size_t TotalNumberOfRuns = 0;
size_t TotalNumberOfExecutedTraceBasedMutations = 0; size_t TotalNumberOfExecutedTraceBasedMutations = 0;

View File

@ -68,10 +68,6 @@ void Fuzzer::SetDeathCallback() {
__sanitizer_set_death_callback(StaticDeathCallback); __sanitizer_set_death_callback(StaticDeathCallback);
} }
void Fuzzer::PrintUnitInASCII(const Unit &U, const char *PrintAfter) {
PrintASCII(U, PrintAfter);
}
void Fuzzer::StaticDeathCallback() { void Fuzzer::StaticDeathCallback() {
assert(F); assert(F);
F->DeathCallback(); F->DeathCallback();
@ -79,11 +75,12 @@ void Fuzzer::StaticDeathCallback() {
void Fuzzer::DeathCallback() { void Fuzzer::DeathCallback() {
Printf("DEATH:\n"); Printf("DEATH:\n");
if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { if (CurrentUnitSize <= kMaxUnitSizeToPrint) {
Print(CurrentUnit, "\n"); PrintHexArray(CurrentUnitData, CurrentUnitSize, "\n");
PrintUnitInASCII(CurrentUnit, "\n"); PrintASCII(CurrentUnitData, CurrentUnitSize, "\n");
} }
WriteUnitToFileWithPrefix(CurrentUnit, "crash-"); WriteUnitToFileWithPrefix(
{CurrentUnitData, CurrentUnitData + CurrentUnitSize}, "crash-");
} }
void Fuzzer::StaticAlarmCallback() { void Fuzzer::StaticAlarmCallback() {
@ -102,11 +99,12 @@ void Fuzzer::AlarmCallback() {
Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
Printf(" and the timeout value is %d (use -timeout=N to change)\n", Printf(" and the timeout value is %d (use -timeout=N to change)\n",
Options.UnitTimeoutSec); Options.UnitTimeoutSec);
if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { if (CurrentUnitSize <= kMaxUnitSizeToPrint) {
Print(CurrentUnit, "\n"); PrintHexArray(CurrentUnitData, CurrentUnitSize, "\n");
PrintUnitInASCII(CurrentUnit, "\n"); PrintASCII(CurrentUnitData, CurrentUnitSize, "\n");
} }
WriteUnitToFileWithPrefix(CurrentUnit, "timeout-"); WriteUnitToFileWithPrefix(
{CurrentUnitData, CurrentUnitData + CurrentUnitSize}, "timeout-");
Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
Seconds); Seconds);
if (__sanitizer_print_stack_trace) if (__sanitizer_print_stack_trace)
@ -163,9 +161,7 @@ void Fuzzer::RereadOutputCorpus() {
if (X.size() > (size_t)Options.MaxLen) if (X.size() > (size_t)Options.MaxLen)
X.resize(Options.MaxLen); X.resize(Options.MaxLen);
if (UnitHashesAddedToCorpus.insert(Hash(X)).second) { if (UnitHashesAddedToCorpus.insert(Hash(X)).second) {
CurrentUnit.clear(); if (RunOne(X)) {
CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end());
if (RunOne(CurrentUnit)) {
Corpus.push_back(X); Corpus.push_back(X);
PrintStats("RELOAD"); PrintStats("RELOAD");
} }
@ -188,7 +184,7 @@ void Fuzzer::ShuffleAndMinimize() {
Corpus.begin(), Corpus.end(), Corpus.begin(), Corpus.end(),
[](const Unit &A, const Unit &B) { return A.size() < B.size(); }); [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
} }
Unit &U = CurrentUnit; Unit U;
for (const auto &C : Corpus) { for (const auto &C : Corpus) {
for (size_t First = 0; First < 1; First++) { for (size_t First = 0; First < 1; First++) {
U.clear(); U.clear();
@ -247,9 +243,13 @@ void Fuzzer::ExecuteCallback(const Unit &U) {
std::unique_ptr<uint8_t[]> Data(new uint8_t[U.size()]); std::unique_ptr<uint8_t[]> Data(new uint8_t[U.size()]);
memcpy(Data.get(), U.data(), U.size()); memcpy(Data.get(), U.data(), U.size());
AssignTaintLabels(Data.get(), U.size()); AssignTaintLabels(Data.get(), U.size());
CurrentUnitData = Data.get();
CurrentUnitSize = U.size();
int Res = USF.TargetFunction(Data.get(), U.size()); int Res = USF.TargetFunction(Data.get(), U.size());
(void)Res; (void)Res;
assert(Res == 0); assert(Res == 0);
CurrentUnitData = nullptr;
CurrentUnitSize = 0;
} }
size_t Fuzzer::RecordBlockCoverage() { size_t Fuzzer::RecordBlockCoverage() {
@ -387,10 +387,9 @@ void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
} }
void Fuzzer::MutateAndTestOne() { void Fuzzer::MutateAndTestOne() {
auto &U = CurrentUnit;
USF.StartMutationSequence(); USF.StartMutationSequence();
U = ChooseUnitToMutate(); auto U = ChooseUnitToMutate();
for (int i = 0; i < Options.MutateDepth; i++) { for (int i = 0; i < Options.MutateDepth; i++) {
size_t Size = U.size(); size_t Size = U.size();
@ -458,15 +457,12 @@ void Fuzzer::Drill() {
PrintStats("REINIT"); PrintStats("REINIT");
SavedOutputCorpusPath.swap(Options.OutputCorpus); SavedOutputCorpusPath.swap(Options.OutputCorpus);
for (auto &U : SavedCorpus) { for (auto &U : SavedCorpus)
CurrentUnit = U;
RunOne(U); RunOne(U);
}
PrintStats("MERGE "); PrintStats("MERGE ");
Options.PrintNEW = true; Options.PrintNEW = true;
size_t NumMerged = 0; size_t NumMerged = 0;
for (auto &U : Corpus) { for (auto &U : Corpus) {
CurrentUnit = U;
if (RunOne(U)) { if (RunOne(U)) {
PrintStatusForNewUnit(U); PrintStatusForNewUnit(U);
NumMerged++; NumMerged++;

View File

@ -41,8 +41,8 @@
// __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK // __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK
// gets all the taint labels for the arguments. // gets all the taint labels for the arguments.
// * At the Fuzzer startup we assign a unique DFSan label // * At the Fuzzer startup we assign a unique DFSan label
// to every byte of the input string (Fuzzer::CurrentUnit) so that for any // to every byte of the input string (Fuzzer::CurrentUnitData) so that
// chunk of data we know which input bytes it has derived from. // for any chunk of data we know which input bytes it has derived from.
// * The __dfsw_* functions (implemented in this file) record the // * The __dfsw_* functions (implemented in this file) record the
// parameters (i.e. the application data and the corresponding taint labels) // parameters (i.e. the application data and the corresponding taint labels)
// in a global state. // in a global state.
@ -174,9 +174,10 @@ const size_t TraceBasedMutation::kMaxSize;
class TraceState { class TraceState {
public: public:
TraceState(UserSuppliedFuzzer &USF, TraceState(UserSuppliedFuzzer &USF, const Fuzzer::FuzzingOptions &Options,
const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit) uint8_t **CurrentUnitData, size_t *CurrentUnitSize)
: USF(USF), Options(Options), CurrentUnit(CurrentUnit) { : USF(USF), Options(Options), CurrentUnitData(CurrentUnitData),
CurrentUnitSize(CurrentUnitSize) {
// Current trace collection is not thread-friendly and it probably // Current trace collection is not thread-friendly and it probably
// does not have to be such, but at least we should not crash in presence // does not have to be such, but at least we should not crash in presence
// of threads. So, just ignore all traces coming from all threads but one. // of threads. So, just ignore all traces coming from all threads but one.
@ -266,7 +267,8 @@ class TraceState {
LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)]; LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)];
UserSuppliedFuzzer &USF; UserSuppliedFuzzer &USF;
const Fuzzer::FuzzingOptions &Options; const Fuzzer::FuzzingOptions &Options;
const Unit &CurrentUnit; uint8_t **CurrentUnitData;
size_t *CurrentUnitSize;
std::map<Unit, size_t> AutoDictUnitCounts; std::map<Unit, size_t> AutoDictUnitCounts;
size_t AutoDictAdds = 0; size_t AutoDictAdds = 0;
static thread_local bool IsMyThread; static thread_local bool IsMyThread;
@ -363,14 +365,14 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
size_t DataSize) { size_t DataSize) {
int Res = 0; int Res = 0;
const uint8_t *Beg = CurrentUnit.data(); const uint8_t *Beg = *CurrentUnitData;
const uint8_t *End = Beg + CurrentUnit.size(); const uint8_t *End = Beg + *CurrentUnitSize;
for (const uint8_t *Cur = Beg; Cur < End; Cur++) { for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize); Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize);
if (!Cur) if (!Cur)
break; break;
size_t Pos = Cur - Beg; size_t Pos = Cur - Beg;
assert(Pos < CurrentUnit.size()); assert(Pos < *CurrentUnitSize);
AddMutation(Pos, DataSize, DesiredData); AddMutation(Pos, DataSize, DesiredData);
AddMutation(Pos, DataSize, DesiredData + 1); AddMutation(Pos, DataSize, DesiredData + 1);
AddMutation(Pos, DataSize, DesiredData - 1); AddMutation(Pos, DataSize, DesiredData - 1);
@ -383,14 +385,14 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
const uint8_t *DesiredData, const uint8_t *DesiredData,
size_t DataSize) { size_t DataSize) {
int Res = 0; int Res = 0;
const uint8_t *Beg = CurrentUnit.data(); const uint8_t *Beg = *CurrentUnitData;
const uint8_t *End = Beg + CurrentUnit.size(); const uint8_t *End = Beg + *CurrentUnitSize;
for (const uint8_t *Cur = Beg; Cur < End; Cur++) { for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize); Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize);
if (!Cur) if (!Cur)
break; break;
size_t Pos = Cur - Beg; size_t Pos = Cur - Beg;
assert(Pos < CurrentUnit.size()); assert(Pos < *CurrentUnitSize);
AddMutation(Pos, DataSize, DesiredData); AddMutation(Pos, DataSize, DesiredData);
Res++; Res++;
} }
@ -468,7 +470,7 @@ void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) {
void Fuzzer::InitializeTraceState() { void Fuzzer::InitializeTraceState() {
if (!Options.UseTraces) return; if (!Options.UseTraces) return;
TS = new TraceState(USF, Options, CurrentUnit); TS = new TraceState(USF, Options, &CurrentUnitData, &CurrentUnitSize);
if (ReallyHaveDFSan()) { if (ReallyHaveDFSan()) {
for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) { for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
dfsan_label L = dfsan_create_label("input", (void *)(i + 1)); dfsan_label L = dfsan_create_label("input", (void *)(i + 1));

View File

@ -21,12 +21,17 @@
namespace fuzzer { namespace fuzzer {
void Print(const Unit &v, const char *PrintAfter) { void PrintHexArray(const uint8_t *Data, size_t Size,
for (auto x : v) const char *PrintAfter) {
Printf("0x%x,", (unsigned) x); for (size_t i = 0; i < Size; i++)
Printf("0x%x,", (unsigned)Data[i]);
Printf("%s", PrintAfter); Printf("%s", PrintAfter);
} }
void Print(const Unit &v, const char *PrintAfter) {
PrintHexArray(v.data(), v.size(), PrintAfter);
}
void PrintASCIIByte(uint8_t Byte) { void PrintASCIIByte(uint8_t Byte) {
if (Byte == '\\') if (Byte == '\\')
Printf("\\\\"); Printf("\\\\");