9347831119d106b2e417caa4ccbad381671999d1
[oota-llvm.git] / lib / Fuzzer / FuzzerLoop.cpp
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 extern "C" {
17 __attribute__((weak)) void __sanitizer_print_stack_trace();
18 }
19
20 namespace fuzzer {
21 static const size_t kMaxUnitSizeToPrint = 256;
22
23 // Only one Fuzzer per process.
24 static Fuzzer *F;
25
26 Fuzzer::Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options)
27     : USF(USF), Options(Options) {
28   SetDeathCallback();
29   InitializeTraceState();
30   assert(!F);
31   F = this;
32 }
33
34 void Fuzzer::SetDeathCallback() {
35   __sanitizer_set_death_callback(StaticDeathCallback);
36 }
37
38 void Fuzzer::PrintUnitInASCII(const Unit &U, const char *PrintAfter) {
39   PrintASCII(U, PrintAfter);
40 }
41
42 void Fuzzer::StaticDeathCallback() {
43   assert(F);
44   F->DeathCallback();
45 }
46
47 void Fuzzer::DeathCallback() {
48   Printf("DEATH:\n");
49   if (CurrentUnit.size() <= kMaxUnitSizeToPrint) {
50     Print(CurrentUnit, "\n");
51     PrintUnitInASCII(CurrentUnit, "\n");
52   }
53   WriteUnitToFileWithPrefix(CurrentUnit, "crash-");
54 }
55
56 void Fuzzer::StaticAlarmCallback() {
57   assert(F);
58   F->AlarmCallback();
59 }
60
61 void Fuzzer::AlarmCallback() {
62   assert(Options.UnitTimeoutSec > 0);
63   size_t Seconds =
64       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
65   if (Seconds == 0) return;
66   if (Options.Verbosity >= 2)
67     Printf("AlarmCallback %zd\n", Seconds);
68   if (Seconds >= (size_t)Options.UnitTimeoutSec) {
69     Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
70     Printf("       and the timeout value is %d (use -timeout=N to change)\n",
71            Options.UnitTimeoutSec);
72     if (CurrentUnit.size() <= kMaxUnitSizeToPrint) {
73       Print(CurrentUnit, "\n");
74       PrintUnitInASCII(CurrentUnit, "\n");
75     }
76     WriteUnitToFileWithPrefix(CurrentUnit, "timeout-");
77     Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
78            Seconds);
79     if (__sanitizer_print_stack_trace)
80       __sanitizer_print_stack_trace();
81     Printf("SUMMARY: libFuzzer: timeout\n");
82     exit(1);
83   }
84 }
85
86 void Fuzzer::PrintStats(const char *Where, size_t Cov, const char *End) {
87   if (!Options.Verbosity) return;
88   size_t Seconds = secondsSinceProcessStartUp();
89   size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0);
90   Printf("#%zd\t%s", TotalNumberOfRuns, Where);
91   Printf(" cov: %zd", Cov);
92   if (auto TB = TotalBits())
93     Printf(" bits: %zd", TB);
94   Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec);
95   if (TotalNumberOfExecutedTraceBasedMutations)
96     Printf(" tbm: %zd", TotalNumberOfExecutedTraceBasedMutations);
97   Printf("%s", End);
98 }
99
100 void Fuzzer::RereadOutputCorpus() {
101   if (Options.OutputCorpus.empty()) return;
102   std::vector<Unit> AdditionalCorpus;
103   ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
104                          &EpochOfLastReadOfOutputCorpus);
105   if (Corpus.empty()) {
106     Corpus = AdditionalCorpus;
107     return;
108   }
109   if (!Options.Reload) return;
110   if (Options.Verbosity >= 2)
111     Printf("Reload: read %zd new units.\n",  AdditionalCorpus.size());
112   for (auto &X : AdditionalCorpus) {
113     if (X.size() > (size_t)Options.MaxLen)
114       X.resize(Options.MaxLen);
115     if (UnitHashesAddedToCorpus.insert(Hash(X)).second) {
116       CurrentUnit.clear();
117       CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end());
118       if (RunOne(CurrentUnit)) {
119         Corpus.push_back(X);
120         if (Options.Verbosity >= 1)
121           PrintStats("RELOAD", LastRecordedBlockCoverage);
122       }
123     }
124   }
125 }
126
127 void Fuzzer::ShuffleAndMinimize() {
128   bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
129                       (Options.PreferSmallDuringInitialShuffle == -1 &&
130                        USF.GetRand().RandBool()));
131   if (Options.Verbosity)
132     Printf("PreferSmall: %d\n", PreferSmall);
133   PrintStats("READ  ", 0);
134   std::vector<Unit> NewCorpus;
135   if (Options.ShuffleAtStartUp) {
136     std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand());
137     if (PreferSmall)
138       std::stable_sort(
139           Corpus.begin(), Corpus.end(),
140           [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
141   }
142   Unit &U = CurrentUnit;
143   for (const auto &C : Corpus) {
144     for (size_t First = 0; First < 1; First++) {
145       U.clear();
146       size_t Last = std::min(First + Options.MaxLen, C.size());
147       U.insert(U.begin(), C.begin() + First, C.begin() + Last);
148       if (Options.OnlyASCII)
149         ToASCII(U);
150       if (RunOne(U)) {
151         NewCorpus.push_back(U);
152         if (Options.Verbosity >= 2)
153           Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size());
154       }
155     }
156   }
157   Corpus = NewCorpus;
158   for (auto &X : Corpus)
159     UnitHashesAddedToCorpus.insert(Hash(X));
160   PrintStats("INITED", LastRecordedBlockCoverage);
161 }
162
163 bool Fuzzer::RunOne(const Unit &U) {
164   UnitStartTime = system_clock::now();
165   TotalNumberOfRuns++;
166
167   PrepareCoverageBeforeRun();
168   ExecuteCallback(U);
169   bool Res = CheckCoverageAfterRun();
170
171   auto UnitStopTime = system_clock::now();
172   auto TimeOfUnit =
173       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
174   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && Options.Verbosity)
175     PrintStats("pulse ", LastRecordedBlockCoverage);
176   if (TimeOfUnit > TimeOfLongestUnitInSeconds &&
177       TimeOfUnit >= Options.ReportSlowUnits) {
178     TimeOfLongestUnitInSeconds = TimeOfUnit;
179     Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
180     WriteUnitToFileWithPrefix(U, "slow-unit-");
181   }
182   return Res;
183 }
184
185 void Fuzzer::RunOneAndUpdateCorpus(Unit &U) {
186   if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
187     return;
188   if (Options.OnlyASCII)
189     ToASCII(U);
190   if (RunOne(U))
191     ReportNewCoverage(U);
192 }
193
194 void Fuzzer::ExecuteCallback(const Unit &U) {
195   int Res = USF.TargetFunction(U.data(), U.size());
196   (void)Res;
197   assert(Res == 0);
198 }
199
200 size_t Fuzzer::RecordBlockCoverage() {
201   return LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage();
202 }
203
204 void Fuzzer::PrepareCoverageBeforeRun() {
205   if (Options.UseCounters) {
206     size_t NumCounters = __sanitizer_get_number_of_counters();
207     CounterBitmap.resize(NumCounters);
208     __sanitizer_update_counter_bitset_and_clear_counters(0);
209   }
210   RecordBlockCoverage();
211 }
212
213 bool Fuzzer::CheckCoverageAfterRun() {
214   size_t OldCoverage = LastRecordedBlockCoverage;
215   size_t NewCoverage = RecordBlockCoverage();
216   size_t NumNewBits = 0;
217   if (Options.UseCounters)
218     NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters(
219         CounterBitmap.data());
220   return NewCoverage > OldCoverage || NumNewBits;
221 }
222
223 void Fuzzer::WriteToOutputCorpus(const Unit &U) {
224   if (Options.OutputCorpus.empty()) return;
225   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
226   WriteToFile(U, Path);
227   if (Options.Verbosity >= 2)
228     Printf("Written to %s\n", Path.c_str());
229   assert(!Options.OnlyASCII || IsASCII(U));
230 }
231
232 void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
233   if (!Options.SaveArtifacts)
234     return;
235   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
236   WriteToFile(U, Path);
237   Printf("artifact_prefix='%s'; Test unit written to %s\n",
238          Options.ArtifactPrefix.c_str(), Path.c_str());
239   if (U.size() <= kMaxUnitSizeToPrint) {
240     Printf("Base64: ");
241     PrintFileAsBase64(Path);
242   }
243 }
244
245 void Fuzzer::SaveCorpus() {
246   if (Options.OutputCorpus.empty()) return;
247   for (const auto &U : Corpus)
248     WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U)));
249   if (Options.Verbosity)
250     Printf("Written corpus of %zd files to %s\n", Corpus.size(),
251            Options.OutputCorpus.c_str());
252 }
253
254 void Fuzzer::ReportNewCoverage(const Unit &U) {
255   Corpus.push_back(U);
256   UnitHashesAddedToCorpus.insert(Hash(U));
257   PrintStats("NEW   ", LastRecordedBlockCoverage, "");
258   if (Options.Verbosity) {
259     Printf(" L: %zd", U.size());
260     if (U.size() < 30) {
261       Printf(" ");
262       PrintUnitInASCII(U, "\t");
263       Print(U);
264     }
265     Printf("\n");
266   }
267   WriteToOutputCorpus(U);
268   if (Options.ExitOnFirst)
269     exit(0);
270 }
271
272 void Fuzzer::MutateAndTestOne(Unit *U) {
273   for (int i = 0; i < Options.MutateDepth; i++) {
274     StartTraceRecording();
275     size_t Size = U->size();
276     U->resize(Options.MaxLen);
277     size_t NewSize = USF.Mutate(U->data(), Size, U->size());
278     assert(NewSize > 0 && "Mutator returned empty unit");
279     assert(NewSize <= (size_t)Options.MaxLen &&
280            "Mutator return overisized unit");
281     U->resize(NewSize);
282     RunOneAndUpdateCorpus(*U);
283     size_t NumTraceBasedMutations = StopTraceRecording();
284     size_t TBMWidth =
285         std::min((size_t)Options.TBMWidth, NumTraceBasedMutations);
286     size_t TBMDepth =
287         std::min((size_t)Options.TBMDepth, NumTraceBasedMutations);
288     Unit BackUp = *U;
289     for (size_t w = 0; w < TBMWidth; w++) {
290       *U = BackUp;
291       for (size_t d = 0; d < TBMDepth; d++) {
292         TotalNumberOfExecutedTraceBasedMutations++;
293         ApplyTraceBasedMutation(USF.GetRand()(NumTraceBasedMutations), U);
294         RunOneAndUpdateCorpus(*U);
295       }
296     }
297   }
298 }
299
300 void Fuzzer::Loop() {
301   for (auto &U: Options.Dictionary)
302     USF.GetMD().AddWordToDictionary(U.data(), U.size());
303
304   while (true) {
305     for (size_t J1 = 0; J1 < Corpus.size(); J1++) {
306       SyncCorpus();
307       RereadOutputCorpus();
308       if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
309         return;
310       if (Options.MaxTotalTimeSec > 0 &&
311           secondsSinceProcessStartUp() >
312               static_cast<size_t>(Options.MaxTotalTimeSec))
313         return;
314       CurrentUnit = Corpus[J1];
315       // Optionally, cross with another unit.
316       if (Options.DoCrossOver && USF.GetRand().RandBool()) {
317         size_t J2 = USF.GetRand()(Corpus.size());
318         if (!Corpus[J1].empty() && !Corpus[J2].empty()) {
319           assert(!Corpus[J2].empty());
320           CurrentUnit.resize(Options.MaxLen);
321           size_t NewSize = USF.CrossOver(
322               Corpus[J1].data(), Corpus[J1].size(), Corpus[J2].data(),
323               Corpus[J2].size(), CurrentUnit.data(), CurrentUnit.size());
324           assert(NewSize > 0 && "CrossOver returned empty unit");
325           assert(NewSize <= (size_t)Options.MaxLen &&
326                  "CrossOver returned overisized unit");
327           CurrentUnit.resize(NewSize);
328         }
329       }
330       // Perform several mutations and runs.
331       MutateAndTestOne(&CurrentUnit);
332     }
333   }
334 }
335
336 void Fuzzer::SyncCorpus() {
337   if (Options.SyncCommand.empty() || Options.OutputCorpus.empty()) return;
338   auto Now = system_clock::now();
339   if (duration_cast<seconds>(Now - LastExternalSync).count() <
340       Options.SyncTimeout)
341     return;
342   LastExternalSync = Now;
343   ExecuteCommand(Options.SyncCommand + " " + Options.OutputCorpus);
344 }
345
346 }  // namespace fuzzer