LLVM  3.7.0
FuzzerLoop.cpp
Go to the documentation of this file.
1 //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // Fuzzer's main loop.
10 //===----------------------------------------------------------------------===//
11 
12 #include "FuzzerInternal.h"
13 #include <sanitizer/coverage_interface.h>
14 #include <algorithm>
15 
16 namespace fuzzer {
17 
18 // Only one Fuzzer per process.
19 static Fuzzer *F;
20 
22  : USF(USF), Options(Options) {
23  SetDeathCallback();
25  assert(!F);
26  F = this;
27 }
28 
29 void Fuzzer::SetDeathCallback() {
30  __sanitizer_set_death_callback(StaticDeathCallback);
31 }
32 
33 void Fuzzer::PrintUnitInASCIIOrTokens(const Unit &U, const char *PrintAfter) {
34  if (Options.Tokens.empty()) {
35  PrintASCII(U, PrintAfter);
36  } else {
37  auto T = SubstituteTokens(U);
38  T.push_back(0);
39  Printf("%s%s", T.data(), PrintAfter);
40  }
41 }
42 
43 void Fuzzer::StaticDeathCallback() {
44  assert(F);
45  F->DeathCallback();
46 }
47 
48 void Fuzzer::DeathCallback() {
49  Printf("DEATH:\n");
50  Print(CurrentUnit, "\n");
51  PrintUnitInASCIIOrTokens(CurrentUnit, "\n");
52  WriteToCrash(CurrentUnit, "crash-");
53 }
54 
56  assert(F);
57  F->AlarmCallback();
58 }
59 
60 void Fuzzer::AlarmCallback() {
61  assert(Options.UnitTimeoutSec > 0);
62  size_t Seconds =
63  duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
64  if (Seconds == 0) return;
65  if (Options.Verbosity >= 2)
66  Printf("AlarmCallback %zd\n", Seconds);
67  if (Seconds >= (size_t)Options.UnitTimeoutSec) {
68  Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
69  Printf(" and the timeout value is %d (use -timeout=N to change)\n",
70  Options.UnitTimeoutSec);
71  Print(CurrentUnit, "\n");
72  PrintUnitInASCIIOrTokens(CurrentUnit, "\n");
73  WriteToCrash(CurrentUnit, "timeout-");
74  exit(1);
75  }
76 }
77 
78 void Fuzzer::PrintStats(const char *Where, size_t Cov, const char *End) {
79  if (!Options.Verbosity) return;
80  size_t Seconds = secondsSinceProcessStartUp();
81  size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0);
82  Printf("#%zd\t%s cov %zd bits %zd units %zd exec/s %zd %s", TotalNumberOfRuns,
83  Where, Cov, TotalBits(), Corpus.size(), ExecPerSec, End);
84 }
85 
87  if (Options.OutputCorpus.empty()) return;
88  std::vector<Unit> AdditionalCorpus;
89  ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
90  &EpochOfLastReadOfOutputCorpus);
91  if (Corpus.empty()) {
92  Corpus = AdditionalCorpus;
93  return;
94  }
95  if (!Options.Reload) return;
96  if (Options.Verbosity >= 2)
97  Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
98  for (auto &X : AdditionalCorpus) {
99  if (X.size() > (size_t)Options.MaxLen)
100  X.resize(Options.MaxLen);
101  if (UnitHashesAddedToCorpus.insert(Hash(X)).second) {
102  CurrentUnit.clear();
103  CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end());
104  size_t NewCoverage = RunOne(CurrentUnit);
105  if (NewCoverage) {
106  Corpus.push_back(X);
107  if (Options.Verbosity >= 1)
108  PrintStats("RELOAD", NewCoverage);
109  }
110  }
111  }
112 }
113 
115  size_t MaxCov = 0;
116  bool PreferSmall =
117  (Options.PreferSmallDuringInitialShuffle == 1 ||
118  (Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2));
119  if (Options.Verbosity)
120  Printf("PreferSmall: %d\n", PreferSmall);
121  PrintStats("READ ", 0);
122  std::vector<Unit> NewCorpus;
123  std::random_shuffle(Corpus.begin(), Corpus.end());
124  if (PreferSmall)
125  std::stable_sort(
126  Corpus.begin(), Corpus.end(),
127  [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
128  Unit &U = CurrentUnit;
129  for (const auto &C : Corpus) {
130  for (size_t First = 0; First < 1; First++) {
131  U.clear();
132  size_t Last = std::min(First + Options.MaxLen, C.size());
133  U.insert(U.begin(), C.begin() + First, C.begin() + Last);
134  size_t NewCoverage = RunOne(U);
135  if (NewCoverage) {
136  MaxCov = NewCoverage;
137  NewCorpus.push_back(U);
138  if (Options.Verbosity >= 2)
139  Printf("NEW0: %zd L %zd\n", NewCoverage, U.size());
140  }
141  }
142  }
143  Corpus = NewCorpus;
144  for (auto &X : Corpus)
145  UnitHashesAddedToCorpus.insert(Hash(X));
146  PrintStats("INITED", MaxCov);
147 }
148 
149 size_t Fuzzer::RunOne(const Unit &U) {
150  UnitStartTime = system_clock::now();
151  TotalNumberOfRuns++;
152  size_t Res = 0;
153  if (Options.UseFullCoverageSet)
154  Res = RunOneMaximizeFullCoverageSet(U);
155  else
156  Res = RunOneMaximizeTotalCoverage(U);
157  auto UnitStopTime = system_clock::now();
158  auto TimeOfUnit =
159  duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
160  if (TimeOfUnit > TimeOfLongestUnitInSeconds) {
161  TimeOfLongestUnitInSeconds = TimeOfUnit;
162  Printf("Longest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
163  Print(U, "\n");
164  }
165  return Res;
166 }
167 
168 void Fuzzer::RunOneAndUpdateCorpus(const Unit &U) {
169  if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
170  return;
171  ReportNewCoverage(RunOne(U), U);
172 }
173 
174 static uintptr_t HashOfArrayOfPCs(uintptr_t *PCs, uintptr_t NumPCs) {
175  uintptr_t Res = 0;
176  for (uintptr_t i = 0; i < NumPCs; i++) {
177  Res = (Res + PCs[i]) * 7;
178  }
179  return Res;
180 }
181 
183  Unit Res;
184  for (auto Idx : U) {
185  if (Idx < Options.Tokens.size()) {
186  std::string Token = Options.Tokens[Idx];
187  Res.insert(Res.end(), Token.begin(), Token.end());
188  } else {
189  Res.push_back(' ');
190  }
191  }
192  // FIXME: Apply DFSan labels.
193  return Res;
194 }
195 
196 void Fuzzer::ExecuteCallback(const Unit &U) {
197  if (Options.Tokens.empty()) {
198  USF.TargetFunction(U.data(), U.size());
199  } else {
200  auto T = SubstituteTokens(U);
201  USF.TargetFunction(T.data(), T.size());
202  }
203 }
204 
205 // Experimental.
206 // Fuly reset the current coverage state, run a single unit,
207 // compute a hash function from the full coverage set,
208 // return non-zero if the hash value is new.
209 // This produces tons of new units and as is it's only suitable for small tests,
210 // e.g. test/FullCoverageSetTest.cpp. FIXME: make it scale.
211 size_t Fuzzer::RunOneMaximizeFullCoverageSet(const Unit &U) {
212  __sanitizer_reset_coverage();
213  ExecuteCallback(U);
214  uintptr_t *PCs;
215  uintptr_t NumPCs =__sanitizer_get_coverage_guards(&PCs);
216  if (FullCoverageSets.insert(HashOfArrayOfPCs(PCs, NumPCs)).second)
217  return FullCoverageSets.size();
218  return 0;
219 }
220 
221 size_t Fuzzer::RunOneMaximizeTotalCoverage(const Unit &U) {
222  size_t NumCounters = __sanitizer_get_number_of_counters();
223  if (Options.UseCounters) {
224  CounterBitmap.resize(NumCounters);
225  __sanitizer_update_counter_bitset_and_clear_counters(0);
226  }
227  size_t OldCoverage = __sanitizer_get_total_unique_coverage();
228  ExecuteCallback(U);
229  size_t NewCoverage = __sanitizer_get_total_unique_coverage();
230  size_t NumNewBits = 0;
231  if (Options.UseCounters)
232  NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters(
233  CounterBitmap.data());
234 
235  if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && Options.Verbosity)
236  PrintStats("pulse ", NewCoverage);
237 
238  if (NewCoverage > OldCoverage || NumNewBits)
239  return NewCoverage;
240  return 0;
241 }
242 
243 void Fuzzer::WriteToOutputCorpus(const Unit &U) {
244  if (Options.OutputCorpus.empty()) return;
245  std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
246  WriteToFile(U, Path);
247  if (Options.Verbosity >= 2)
248  Printf("Written to %s\n", Path.c_str());
249 }
250 
251 void Fuzzer::WriteToCrash(const Unit &U, const char *Prefix) {
252  std::string Path = Prefix + Hash(U);
253  WriteToFile(U, Path);
254  Printf("CRASHED; file written to %s\nBase64: ", Path.c_str());
255  PrintFileAsBase64(Path);
256 }
257 
259  if (Options.OutputCorpus.empty()) return;
260  for (const auto &U : Corpus)
261  WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U)));
262  if (Options.Verbosity)
263  Printf("Written corpus of %zd files to %s\n", Corpus.size(),
264  Options.OutputCorpus.c_str());
265 }
266 
267 void Fuzzer::ReportNewCoverage(size_t NewCoverage, const Unit &U) {
268  if (!NewCoverage) return;
269  Corpus.push_back(U);
270  UnitHashesAddedToCorpus.insert(Hash(U));
271  PrintStats("NEW ", NewCoverage, "");
272  if (Options.Verbosity) {
273  Printf(" L: %zd", U.size());
274  if (U.size() < 30) {
275  Printf(" ");
276  PrintUnitInASCIIOrTokens(U, "\t");
277  Print(U);
278  }
279  Printf("\n");
280  }
281  WriteToOutputCorpus(U);
282  if (Options.ExitOnFirst)
283  exit(0);
284 }
285 
286 void Fuzzer::MutateAndTestOne(Unit *U) {
287  for (int i = 0; i < Options.MutateDepth; i++) {
288  StartTraceRecording();
289  size_t Size = U->size();
290  U->resize(Options.MaxLen);
291  size_t NewSize = USF.Mutate(U->data(), Size, U->size());
292  assert(NewSize > 0 && "Mutator returned empty unit");
293  assert(NewSize <= (size_t)Options.MaxLen &&
294  "Mutator return overisized unit");
295  U->resize(NewSize);
296  RunOneAndUpdateCorpus(*U);
297  size_t NumTraceBasedMutations = StopTraceRecording();
298  for (size_t j = 0; j < NumTraceBasedMutations; j++) {
299  ApplyTraceBasedMutation(j, U);
300  RunOneAndUpdateCorpus(*U);
301  }
302  }
303 }
304 
305 void Fuzzer::Loop(size_t NumIterations) {
306  for (size_t i = 1; i <= NumIterations; i++) {
307  for (size_t J1 = 0; J1 < Corpus.size(); J1++) {
308  SyncCorpus();
310  if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
311  return;
312  // First, simply mutate the unit w/o doing crosses.
313  CurrentUnit = Corpus[J1];
314  MutateAndTestOne(&CurrentUnit);
315  // Now, cross with others.
316  if (Options.DoCrossOver && !Corpus[J1].empty()) {
317  for (size_t J2 = 0; J2 < Corpus.size(); J2++) {
318  CurrentUnit.resize(Options.MaxLen);
319  size_t NewSize = USF.CrossOver(
320  Corpus[J1].data(), Corpus[J1].size(), Corpus[J2].data(),
321  Corpus[J2].size(), CurrentUnit.data(), CurrentUnit.size());
322  assert(NewSize > 0 && "CrossOver returned empty unit");
323  assert(NewSize <= (size_t)Options.MaxLen &&
324  "CrossOver return overisized unit");
325  CurrentUnit.resize(NewSize);
326  MutateAndTestOne(&CurrentUnit);
327  }
328  }
329  }
330  }
331 }
332 
333 void Fuzzer::SyncCorpus() {
334  if (Options.SyncCommand.empty() || Options.OutputCorpus.empty()) return;
335  auto Now = system_clock::now();
336  if (duration_cast<seconds>(Now - LastExternalSync).count() <
337  Options.SyncTimeout)
338  return;
339  LastExternalSync = Now;
340  ExecuteCommand(Options.SyncCommand + " " + Options.OutputCorpus);
341 }
342 
343 } // namespace fuzzer
void RereadOutputCorpus()
Definition: FuzzerLoop.cpp:86
void PrintASCII(const Unit &U, const char *PrintAfter="")
Definition: FuzzerUtil.cpp:29
void ShuffleAndMinimize()
Definition: FuzzerLoop.cpp:114
void Print(const Unit &U, const char *PrintAfter="")
Definition: FuzzerUtil.cpp:23
Unit SubstituteTokens(const Unit &U) const
Definition: FuzzerLoop.cpp:182
void Loop(size_t NumIterations)
Definition: FuzzerLoop.cpp:305
std::vector< std::string > Tokens
size_t secondsSinceProcessStartUp()
void ExecuteCommand(const std::string &Command)
Definition: FuzzerUtil.cpp:72
static Fuzzer * F
Definition: FuzzerLoop.cpp:19
void PrintFileAsBase64(const std::string &Path)
Definition: FuzzerIO.cpp:82
virtual size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize)
Crosses 'Data1' and 'Data2', writes up to 'MaxOutSize' bytes into Out, returns the number of bytes wr...
Number of individual test Apply this number of consecutive mutations to each input exit after the first new interesting input is found the minimized corpus is saved into the first input directory Number of jobs to run If min(jobs, NumberOfCpuCores()/2)\" is used.") FUZZER_FLAG_INT(reload
void Printf(const char *Fmt,...)
Definition: FuzzerIO.cpp:87
static PassOptionList PrintAfter("print-after", llvm::cl::desc("Print IR after specified passes"), cl::Hidden)
static uintptr_t HashOfArrayOfPCs(uintptr_t *PCs, uintptr_t NumPCs)
Definition: FuzzerLoop.cpp:174
std::string DirPlusFile(const std::string &DirPath, const std::string &FileName)
Definition: FuzzerIO.cpp:77
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang","erlang-compatible garbage collector")
An abstract class that allows to use user-supplied mutators with libFuzzer.
Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options)
Definition: FuzzerLoop.cpp:21
void WriteToFile(const Unit &U, const std::string &Path)
Definition: FuzzerIO.cpp:62
static void StaticAlarmCallback()
Definition: FuzzerLoop.cpp:55
void size_t size
std::vector< uint8_t > Unit
void ReadDirToVectorOfUnits(const char *Path, std::vector< Unit > *V, long *Epoch)
Definition: FuzzerIO.cpp:67
std::string Hash(const Unit &U)
Definition: FuzzerUtil.cpp:39
static sys::TimeValue now(bool Deterministic)
virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize)
Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes, returns the new size of th...
virtual void TargetFunction(const uint8_t *Data, size_t Size)=0
Executes the target function on 'Size' bytes of 'Data'.