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