/src/mozilla-central/tools/fuzzing/libfuzzer/FuzzerLoop.cpp
Line | Count | Source (jump to first uncovered line) |
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 "FuzzerCorpus.h" |
13 | | #include "FuzzerIO.h" |
14 | | #include "FuzzerInternal.h" |
15 | | #include "FuzzerMutate.h" |
16 | | #include "FuzzerRandom.h" |
17 | | #include "FuzzerShmem.h" |
18 | | #include "FuzzerTracePC.h" |
19 | | #include <algorithm> |
20 | | #include <cstring> |
21 | | #include <memory> |
22 | | #include <mutex> |
23 | | #include <set> |
24 | | |
25 | | #if defined(__has_include) |
26 | | #if __has_include(<sanitizer / lsan_interface.h>) |
27 | | #include <sanitizer/lsan_interface.h> |
28 | | #endif |
29 | | #endif |
30 | | |
31 | | #define NO_SANITIZE_MEMORY |
32 | | #if defined(__has_feature) |
33 | | #if __has_feature(memory_sanitizer) |
34 | | #undef NO_SANITIZE_MEMORY |
35 | | #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) |
36 | | #endif |
37 | | #endif |
38 | | |
39 | | namespace fuzzer { |
40 | | static const size_t kMaxUnitSizeToPrint = 256; |
41 | | |
42 | | thread_local bool Fuzzer::IsMyThread; |
43 | | |
44 | | SharedMemoryRegion SMR; |
45 | | |
46 | | bool RunningUserCallback = false; |
47 | | |
48 | | // Only one Fuzzer per process. |
49 | | static Fuzzer *F; |
50 | | |
51 | | // Leak detection is expensive, so we first check if there were more mallocs |
52 | | // than frees (using the sanitizer malloc hooks) and only then try to call lsan. |
53 | | struct MallocFreeTracer { |
54 | 16.2k | void Start(int TraceLevel) { |
55 | 16.2k | this->TraceLevel = TraceLevel; |
56 | 16.2k | if (TraceLevel) |
57 | 0 | Printf("MallocFreeTracer: START\n"); |
58 | 16.2k | Mallocs = 0; |
59 | 16.2k | Frees = 0; |
60 | 16.2k | } |
61 | | // Returns true if there were more mallocs than frees. |
62 | 16.2k | bool Stop() { |
63 | 16.2k | if (TraceLevel) |
64 | 0 | Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), |
65 | 0 | Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); |
66 | 16.2k | bool Result = Mallocs > Frees; |
67 | 16.2k | Mallocs = 0; |
68 | 16.2k | Frees = 0; |
69 | 16.2k | TraceLevel = 0; |
70 | 16.2k | return Result; |
71 | 16.2k | } |
72 | | std::atomic<size_t> Mallocs; |
73 | | std::atomic<size_t> Frees; |
74 | | int TraceLevel = 0; |
75 | | |
76 | | std::recursive_mutex TraceMutex; |
77 | | bool TraceDisabled = false; |
78 | | }; |
79 | | |
80 | | static MallocFreeTracer AllocTracer; |
81 | | |
82 | | // Locks printing and avoids nested hooks triggered from mallocs/frees in |
83 | | // sanitizer. |
84 | | class TraceLock { |
85 | | public: |
86 | 0 | TraceLock() : Lock(AllocTracer.TraceMutex) { |
87 | 0 | AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; |
88 | 0 | } |
89 | 0 | ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; } |
90 | | |
91 | 0 | bool IsDisabled() const { |
92 | 0 | // This is already inverted value. |
93 | 0 | return !AllocTracer.TraceDisabled; |
94 | 0 | } |
95 | | |
96 | | private: |
97 | | std::lock_guard<std::recursive_mutex> Lock; |
98 | | }; |
99 | | |
100 | | ATTRIBUTE_NO_SANITIZE_MEMORY |
101 | 0 | void MallocHook(const volatile void *ptr, size_t size) { |
102 | 0 | size_t N = AllocTracer.Mallocs++; |
103 | 0 | F->HandleMalloc(size); |
104 | 0 | if (int TraceLevel = AllocTracer.TraceLevel) { |
105 | 0 | TraceLock Lock; |
106 | 0 | if (Lock.IsDisabled()) |
107 | 0 | return; |
108 | 0 | Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); |
109 | 0 | if (TraceLevel >= 2 && EF) |
110 | 0 | PrintStackTrace(); |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | ATTRIBUTE_NO_SANITIZE_MEMORY |
115 | 0 | void FreeHook(const volatile void *ptr) { |
116 | 0 | size_t N = AllocTracer.Frees++; |
117 | 0 | if (int TraceLevel = AllocTracer.TraceLevel) { |
118 | 0 | TraceLock Lock; |
119 | 0 | if (Lock.IsDisabled()) |
120 | 0 | return; |
121 | 0 | Printf("FREE[%zd] %p\n", N, ptr); |
122 | 0 | if (TraceLevel >= 2 && EF) |
123 | 0 | PrintStackTrace(); |
124 | 0 | } |
125 | 0 | } |
126 | | |
127 | | // Crash on a single malloc that exceeds the rss limit. |
128 | 0 | void Fuzzer::HandleMalloc(size_t Size) { |
129 | 0 | if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb) |
130 | 0 | return; |
131 | 0 | Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), |
132 | 0 | Size); |
133 | 0 | Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); |
134 | 0 | PrintStackTrace(); |
135 | 0 | DumpCurrentUnit("oom-"); |
136 | 0 | Printf("SUMMARY: libFuzzer: out-of-memory\n"); |
137 | 0 | PrintFinalStats(); |
138 | 0 | _Exit(Options.ErrorExitCode); // Stop right now. |
139 | 0 | } |
140 | | |
141 | | Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, |
142 | | FuzzingOptions Options) |
143 | 3 | : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { |
144 | 3 | if (EF->__sanitizer_set_death_callback) |
145 | 3 | EF->__sanitizer_set_death_callback(StaticDeathCallback); |
146 | 3 | assert(!F); |
147 | 3 | F = this; |
148 | 3 | TPC.ResetMaps(); |
149 | 3 | IsMyThread = true; |
150 | 3 | if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) |
151 | 3 | EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); |
152 | 3 | TPC.SetUseCounters(Options.UseCounters); |
153 | 3 | TPC.SetUseValueProfileMask(Options.UseValueProfile); |
154 | 3 | |
155 | 3 | if (Options.Verbosity) |
156 | 3 | TPC.PrintModuleInfo(); |
157 | 3 | if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) |
158 | 3 | EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); |
159 | 3 | MaxInputLen = MaxMutationLen = Options.MaxLen; |
160 | 3 | TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize()); |
161 | 3 | AllocateCurrentUnitData(); |
162 | 3 | CurrentUnitSize = 0; |
163 | 3 | memset(BaseSha1, 0, sizeof(BaseSha1)); |
164 | 3 | TPC.SetFocusFunction(Options.FocusFunction); |
165 | 3 | DFT.Init(Options.DataFlowTrace, Options.FocusFunction); |
166 | 3 | } |
167 | | |
168 | 0 | Fuzzer::~Fuzzer() {} |
169 | | |
170 | 6 | void Fuzzer::AllocateCurrentUnitData() { |
171 | 6 | if (CurrentUnitData || MaxInputLen == 0) |
172 | 3 | return; |
173 | 3 | CurrentUnitData = new uint8_t[MaxInputLen]; |
174 | 3 | } |
175 | | |
176 | 0 | void Fuzzer::StaticDeathCallback() { |
177 | 0 | assert(F); |
178 | 0 | F->DeathCallback(); |
179 | 0 | } |
180 | | |
181 | 0 | void Fuzzer::DumpCurrentUnit(const char *Prefix) { |
182 | 0 | if (!CurrentUnitData) |
183 | 0 | return; // Happens when running individual inputs. |
184 | 0 | ScopedDisableMsanInterceptorChecks S; |
185 | 0 | MD.PrintMutationSequence(); |
186 | 0 | Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); |
187 | 0 | size_t UnitSize = CurrentUnitSize; |
188 | 0 | if (UnitSize <= kMaxUnitSizeToPrint) { |
189 | 0 | PrintHexArray(CurrentUnitData, UnitSize, "\n"); |
190 | 0 | PrintASCII(CurrentUnitData, UnitSize, "\n"); |
191 | 0 | } |
192 | 0 | WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, |
193 | 0 | Prefix); |
194 | 0 | } |
195 | | |
196 | | NO_SANITIZE_MEMORY |
197 | 0 | void Fuzzer::DeathCallback() { |
198 | 0 | DumpCurrentUnit("crash-"); |
199 | 0 | PrintFinalStats(); |
200 | 0 | } |
201 | | |
202 | 14 | void Fuzzer::StaticAlarmCallback() { |
203 | 14 | assert(F); |
204 | 14 | F->AlarmCallback(); |
205 | 14 | } |
206 | | |
207 | 0 | void Fuzzer::StaticCrashSignalCallback() { |
208 | 0 | assert(F); |
209 | 0 | F->CrashCallback(); |
210 | 0 | } |
211 | | |
212 | 3 | void Fuzzer::StaticExitCallback() { |
213 | 3 | assert(F); |
214 | 3 | F->ExitCallback(); |
215 | 3 | } |
216 | | |
217 | 0 | void Fuzzer::StaticInterruptCallback() { |
218 | 0 | assert(F); |
219 | 0 | F->InterruptCallback(); |
220 | 0 | } |
221 | | |
222 | 0 | void Fuzzer::StaticGracefulExitCallback() { |
223 | 0 | assert(F); |
224 | 0 | F->GracefulExitRequested = true; |
225 | 0 | Printf("INFO: signal received, trying to exit gracefully\n"); |
226 | 0 | } |
227 | | |
228 | 0 | void Fuzzer::StaticFileSizeExceedCallback() { |
229 | 0 | Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); |
230 | 0 | exit(1); |
231 | 0 | } |
232 | | |
233 | 0 | void Fuzzer::CrashCallback() { |
234 | 0 | if (EF->__sanitizer_acquire_crash_state) |
235 | 0 | EF->__sanitizer_acquire_crash_state(); |
236 | 0 | Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); |
237 | 0 | PrintStackTrace(); |
238 | 0 | Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" |
239 | 0 | " Combine libFuzzer with AddressSanitizer or similar for better " |
240 | 0 | "crash reports.\n"); |
241 | 0 | Printf("SUMMARY: libFuzzer: deadly signal\n"); |
242 | 0 | DumpCurrentUnit("crash-"); |
243 | 0 | PrintFinalStats(); |
244 | 0 | _Exit(Options.ErrorExitCode); // Stop right now. |
245 | 0 | } |
246 | | |
247 | 3 | void Fuzzer::ExitCallback() { |
248 | 3 | if (!RunningUserCallback) |
249 | 3 | return; // This exit did not come from the user callback |
250 | 0 | if (EF->__sanitizer_acquire_crash_state && |
251 | 0 | !EF->__sanitizer_acquire_crash_state()) |
252 | 0 | return; |
253 | 0 | Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); |
254 | 0 | PrintStackTrace(); |
255 | 0 | Printf("SUMMARY: libFuzzer: fuzz target exited\n"); |
256 | 0 | DumpCurrentUnit("crash-"); |
257 | 0 | PrintFinalStats(); |
258 | 0 | _Exit(Options.ErrorExitCode); |
259 | 0 | } |
260 | | |
261 | 0 | void Fuzzer::MaybeExitGracefully() { |
262 | 0 | if (!GracefulExitRequested) return; |
263 | 0 | Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid()); |
264 | 0 | PrintFinalStats(); |
265 | 0 | _Exit(0); |
266 | 0 | } |
267 | | |
268 | 0 | void Fuzzer::InterruptCallback() { |
269 | 0 | Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); |
270 | 0 | PrintFinalStats(); |
271 | 0 | _Exit(0); // Stop right now, don't perform any at-exit actions. |
272 | 0 | } |
273 | | |
274 | | NO_SANITIZE_MEMORY |
275 | 14 | void Fuzzer::AlarmCallback() { |
276 | 14 | assert(Options.UnitTimeoutSec > 0); |
277 | 14 | // In Windows Alarm callback is executed by a different thread. |
278 | 14 | #if !LIBFUZZER_WINDOWS |
279 | 14 | if (!InFuzzingThread()) |
280 | 0 | return; |
281 | 14 | #endif |
282 | 14 | if (!RunningUserCallback) |
283 | 0 | return; // We have not started running units yet. |
284 | 14 | size_t Seconds = |
285 | 14 | duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); |
286 | 14 | if (Seconds == 0) |
287 | 6 | return; |
288 | 8 | if (Options.Verbosity >= 2) |
289 | 0 | Printf("AlarmCallback %zd\n", Seconds); |
290 | 8 | if (Seconds >= (size_t)Options.UnitTimeoutSec) { |
291 | 0 | if (EF->__sanitizer_acquire_crash_state && |
292 | 0 | !EF->__sanitizer_acquire_crash_state()) |
293 | 0 | return; |
294 | 0 | Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); |
295 | 0 | Printf(" and the timeout value is %d (use -timeout=N to change)\n", |
296 | 0 | Options.UnitTimeoutSec); |
297 | 0 | DumpCurrentUnit("timeout-"); |
298 | 0 | Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), |
299 | 0 | Seconds); |
300 | 0 | PrintStackTrace(); |
301 | 0 | Printf("SUMMARY: libFuzzer: timeout\n"); |
302 | 0 | PrintFinalStats(); |
303 | 0 | _Exit(Options.TimeoutExitCode); // Stop right now. |
304 | 0 | } |
305 | 8 | } |
306 | | |
307 | 0 | void Fuzzer::RssLimitCallback() { |
308 | 0 | if (EF->__sanitizer_acquire_crash_state && |
309 | 0 | !EF->__sanitizer_acquire_crash_state()) |
310 | 0 | return; |
311 | 0 | Printf( |
312 | 0 | "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", |
313 | 0 | GetPid(), GetPeakRSSMb(), Options.RssLimitMb); |
314 | 0 | Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); |
315 | 0 | PrintMemoryProfile(); |
316 | 0 | DumpCurrentUnit("oom-"); |
317 | 0 | Printf("SUMMARY: libFuzzer: out-of-memory\n"); |
318 | 0 | PrintFinalStats(); |
319 | 0 | _Exit(Options.ErrorExitCode); // Stop right now. |
320 | 0 | } |
321 | | |
322 | 14 | void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { |
323 | 14 | size_t ExecPerSec = execPerSec(); |
324 | 14 | if (!Options.Verbosity) |
325 | 0 | return; |
326 | 14 | Printf("#%zd\t%s", TotalNumberOfRuns, Where); |
327 | 14 | if (size_t N = TPC.GetTotalPCCoverage()) |
328 | 14 | Printf(" cov: %zd", N); |
329 | 14 | if (size_t N = Corpus.NumFeatures()) |
330 | 14 | Printf(" ft: %zd", N); |
331 | 14 | if (!Corpus.empty()) { |
332 | 14 | Printf(" corp: %zd", Corpus.NumActiveUnits()); |
333 | 14 | if (size_t N = Corpus.SizeInBytes()) { |
334 | 14 | if (N < (1 << 14)) |
335 | 4 | Printf("/%zdb", N); |
336 | 10 | else if (N < (1 << 24)) |
337 | 10 | Printf("/%zdKb", N >> 10); |
338 | 0 | else |
339 | 0 | Printf("/%zdMb", N >> 20); |
340 | 14 | } |
341 | 14 | if (size_t FF = Corpus.NumInputsThatTouchFocusFunction()) |
342 | 0 | Printf(" focus: %zd", FF); |
343 | 14 | } |
344 | 14 | if (TmpMaxMutationLen) |
345 | 14 | Printf(" lim: %zd", TmpMaxMutationLen); |
346 | 14 | if (Units) |
347 | 0 | Printf(" units: %zd", Units); |
348 | 14 | |
349 | 14 | Printf(" exec/s: %zd", ExecPerSec); |
350 | 14 | Printf(" rss: %zdMb", GetPeakRSSMb()); |
351 | 14 | Printf("%s", End); |
352 | 14 | } |
353 | | |
354 | 3 | void Fuzzer::PrintFinalStats() { |
355 | 3 | if (Options.PrintCoverage) |
356 | 0 | TPC.PrintCoverage(); |
357 | 3 | if (Options.PrintUnstableStats) |
358 | 0 | TPC.PrintUnstableStats(); |
359 | 3 | if (Options.DumpCoverage) |
360 | 0 | TPC.DumpCoverage(); |
361 | 3 | if (Options.PrintCorpusStats) |
362 | 0 | Corpus.PrintStats(); |
363 | 3 | if (!Options.PrintFinalStats) |
364 | 3 | return; |
365 | 0 | size_t ExecPerSec = execPerSec(); |
366 | 0 | Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); |
367 | 0 | Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); |
368 | 0 | Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); |
369 | 0 | Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); |
370 | 0 | Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); |
371 | 0 | } |
372 | | |
373 | 3 | void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { |
374 | 3 | assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. |
375 | 3 | assert(MaxInputLen); |
376 | 3 | this->MaxInputLen = MaxInputLen; |
377 | 3 | this->MaxMutationLen = MaxInputLen; |
378 | 3 | AllocateCurrentUnitData(); |
379 | 3 | Printf("INFO: -max_len is not provided; " |
380 | 3 | "libFuzzer will not generate inputs larger than %zd bytes\n", |
381 | 3 | MaxInputLen); |
382 | 3 | } |
383 | | |
384 | 0 | void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { |
385 | 0 | assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); |
386 | 0 | this->MaxMutationLen = MaxMutationLen; |
387 | 0 | } |
388 | | |
389 | 16.2k | void Fuzzer::CheckExitOnSrcPosOrItem() { |
390 | 16.2k | if (!Options.ExitOnSrcPos.empty()) { |
391 | 0 | static auto *PCsSet = new Set<uintptr_t>; |
392 | 0 | auto HandlePC = [&](uintptr_t PC) { |
393 | 0 | if (!PCsSet->insert(PC).second) |
394 | 0 | return; |
395 | 0 | std::string Descr = DescribePC("%F %L", PC + 1); |
396 | 0 | if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { |
397 | 0 | Printf("INFO: found line matching '%s', exiting.\n", |
398 | 0 | Options.ExitOnSrcPos.c_str()); |
399 | 0 | _Exit(0); |
400 | 0 | } |
401 | 0 | }; |
402 | 0 | TPC.ForEachObservedPC(HandlePC); |
403 | 0 | } |
404 | 16.2k | if (!Options.ExitOnItem.empty()) { |
405 | 0 | if (Corpus.HasUnit(Options.ExitOnItem)) { |
406 | 0 | Printf("INFO: found item with checksum '%s', exiting.\n", |
407 | 0 | Options.ExitOnItem.c_str()); |
408 | 0 | _Exit(0); |
409 | 0 | } |
410 | 0 | } |
411 | 16.2k | } |
412 | | |
413 | 0 | void Fuzzer::RereadOutputCorpus(size_t MaxSize) { |
414 | 0 | if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) |
415 | 0 | return; |
416 | 0 | Vector<Unit> AdditionalCorpus; |
417 | 0 | ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, |
418 | 0 | &EpochOfLastReadOfOutputCorpus, MaxSize, |
419 | 0 | /*ExitOnError*/ false); |
420 | 0 | if (Options.Verbosity >= 2) |
421 | 0 | Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); |
422 | 0 | bool Reloaded = false; |
423 | 0 | for (auto &U : AdditionalCorpus) { |
424 | 0 | if (U.size() > MaxSize) |
425 | 0 | U.resize(MaxSize); |
426 | 0 | if (!Corpus.HasUnit(U)) { |
427 | 0 | if (RunOne(U.data(), U.size())) { |
428 | 0 | CheckExitOnSrcPosOrItem(); |
429 | 0 | Reloaded = true; |
430 | 0 | } |
431 | 0 | } |
432 | 0 | } |
433 | 0 | if (Reloaded) |
434 | 0 | PrintStats("RELOAD"); |
435 | 0 | } |
436 | | |
437 | 16.2k | void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { |
438 | 16.2k | auto TimeOfUnit = |
439 | 16.2k | duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); |
440 | 16.2k | if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && |
441 | 16.2k | secondsSinceProcessStartUp() >= 2) |
442 | 8 | PrintStats("pulse "); |
443 | 16.2k | if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && |
444 | 16.2k | TimeOfUnit >= Options.ReportSlowUnits) { |
445 | 0 | TimeOfLongestUnitInSeconds = TimeOfUnit; |
446 | 0 | Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); |
447 | 0 | WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); |
448 | 0 | } |
449 | 16.2k | } |
450 | | |
451 | 0 | void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) { |
452 | 0 | auto CBSetupAndRun = [&]() { |
453 | 0 | ScopedEnableMsanInterceptorChecks S; |
454 | 0 | UnitStartTime = system_clock::now(); |
455 | 0 | TPC.ResetMaps(); |
456 | 0 | RunningUserCallback = true; |
457 | 0 | CB(Data, Size); |
458 | 0 | RunningUserCallback = false; |
459 | 0 | UnitStopTime = system_clock::now(); |
460 | 0 | }; |
461 | 0 |
|
462 | 0 | // Copy original run counters into our unstable counters |
463 | 0 | TPC.InitializeUnstableCounters(); |
464 | 0 |
|
465 | 0 | // First Rerun |
466 | 0 | CBSetupAndRun(); |
467 | 0 | if (TPC.UpdateUnstableCounters(Options.HandleUnstable)) { |
468 | 0 | // Second Rerun |
469 | 0 | CBSetupAndRun(); |
470 | 0 | TPC.UpdateAndApplyUnstableCounters(Options.HandleUnstable); |
471 | 0 | } |
472 | 0 | } |
473 | | |
474 | | bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, |
475 | 16.2k | InputInfo *II, bool *FoundUniqFeatures) { |
476 | 16.2k | if (!Size) |
477 | 0 | return false; |
478 | 16.2k | |
479 | 16.2k | ExecuteCallback(Data, Size); |
480 | 16.2k | |
481 | 16.2k | UniqFeatureSetTmp.clear(); |
482 | 16.2k | size_t FoundUniqFeaturesOfII = 0; |
483 | 16.2k | size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); |
484 | 16.2k | bool NewFeaturesUnstable = false; |
485 | 16.2k | |
486 | 16.2k | if (Options.HandleUnstable || Options.PrintUnstableStats) { |
487 | 0 | TPC.CollectFeatures([&](size_t Feature) { |
488 | 0 | if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink)) |
489 | 0 | NewFeaturesUnstable = true; |
490 | 0 | }); |
491 | 0 | if (NewFeaturesUnstable) |
492 | 0 | CheckForUnstableCounters(Data, Size); |
493 | 0 | } |
494 | 16.2k | |
495 | 10.5M | TPC.CollectFeatures([&](size_t Feature) { |
496 | 10.5M | if (Corpus.AddFeature(Feature, Size, Options.Shrink)) |
497 | 62.7k | UniqFeatureSetTmp.push_back(Feature); |
498 | 10.5M | if (Options.ReduceInputs && II) |
499 | 0 | if (std::binary_search(II->UniqFeatureSet.begin(), |
500 | 0 | II->UniqFeatureSet.end(), Feature)) |
501 | 0 | FoundUniqFeaturesOfII++; |
502 | 10.5M | }); |
503 | 16.2k | |
504 | 16.2k | if (FoundUniqFeatures) |
505 | 0 | *FoundUniqFeatures = FoundUniqFeaturesOfII; |
506 | 16.2k | PrintPulseAndReportSlowInput(Data, Size); |
507 | 16.2k | size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; |
508 | 16.2k | |
509 | 16.2k | if (NumNewFeatures) { |
510 | 10.4k | TPC.UpdateObservedPCs(); |
511 | 10.4k | Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, |
512 | 10.4k | TPC.ObservedFocusFunction(), UniqFeatureSetTmp, DFT, II); |
513 | 10.4k | return true; |
514 | 10.4k | } |
515 | 5.79k | if (II && FoundUniqFeaturesOfII && |
516 | 5.79k | II->DataFlowTraceForFocusFunction.empty() && |
517 | 5.79k | FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && |
518 | 5.79k | II->U.size() > Size) { |
519 | 0 | Corpus.Replace(II, {Data, Data + Size}); |
520 | 0 | return true; |
521 | 0 | } |
522 | 5.79k | return false; |
523 | 5.79k | } |
524 | | |
525 | 0 | size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { |
526 | 0 | assert(InFuzzingThread()); |
527 | 0 | *Data = CurrentUnitData; |
528 | 0 | return CurrentUnitSize; |
529 | 0 | } |
530 | | |
531 | 0 | void Fuzzer::CrashOnOverwrittenData() { |
532 | 0 | Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n", |
533 | 0 | GetPid()); |
534 | 0 | DumpCurrentUnit("crash-"); |
535 | 0 | Printf("SUMMARY: libFuzzer: out-of-memory\n"); |
536 | 0 | _Exit(Options.ErrorExitCode); // Stop right now. |
537 | 0 | } |
538 | | |
539 | | // Compare two arrays, but not all bytes if the arrays are large. |
540 | 16.2k | static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { |
541 | 16.2k | const size_t Limit = 64; |
542 | 16.2k | if (Size <= 64) |
543 | 7.76k | return !memcmp(A, B, Size); |
544 | 8.46k | // Compare first and last Limit/2 bytes. |
545 | 8.46k | return !memcmp(A, B, Limit / 2) && |
546 | 8.46k | !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); |
547 | 8.46k | } |
548 | | |
549 | 16.2k | void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { |
550 | 16.2k | TPC.RecordInitialStack(); |
551 | 16.2k | TotalNumberOfRuns++; |
552 | 16.2k | assert(InFuzzingThread()); |
553 | 16.2k | if (SMR.IsClient()) |
554 | 0 | SMR.WriteByteArray(Data, Size); |
555 | 16.2k | // We copy the contents of Unit into a separate heap buffer |
556 | 16.2k | // so that we reliably find buffer overflows in it. |
557 | 16.2k | uint8_t *DataCopy = new uint8_t[Size]; |
558 | 16.2k | memcpy(DataCopy, Data, Size); |
559 | 16.2k | if (EF->__msan_unpoison) |
560 | 0 | EF->__msan_unpoison(DataCopy, Size); |
561 | 16.2k | if (CurrentUnitData && CurrentUnitData != Data) |
562 | 16.2k | memcpy(CurrentUnitData, Data, Size); |
563 | 16.2k | CurrentUnitSize = Size; |
564 | 16.2k | { |
565 | 16.2k | ScopedEnableMsanInterceptorChecks S; |
566 | 16.2k | AllocTracer.Start(Options.TraceMalloc); |
567 | 16.2k | UnitStartTime = system_clock::now(); |
568 | 16.2k | TPC.ResetMaps(); |
569 | 16.2k | RunningUserCallback = true; |
570 | 16.2k | int Res = CB(DataCopy, Size); |
571 | 16.2k | RunningUserCallback = false; |
572 | 16.2k | UnitStopTime = system_clock::now(); |
573 | 16.2k | (void)Res; |
574 | 16.2k | assert(Res == 0); |
575 | 16.2k | HasMoreMallocsThanFrees = AllocTracer.Stop(); |
576 | 16.2k | } |
577 | 16.2k | if (!LooseMemeq(DataCopy, Data, Size)) |
578 | 0 | CrashOnOverwrittenData(); |
579 | 16.2k | CurrentUnitSize = 0; |
580 | 16.2k | delete[] DataCopy; |
581 | 16.2k | } |
582 | | |
583 | 0 | void Fuzzer::WriteToOutputCorpus(const Unit &U) { |
584 | 0 | if (Options.OnlyASCII) |
585 | 0 | assert(IsASCII(U)); |
586 | 0 | if (Options.OutputCorpus.empty()) |
587 | 0 | return; |
588 | 0 | std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); |
589 | 0 | WriteToFile(U, Path); |
590 | 0 | if (Options.Verbosity >= 2) |
591 | 0 | Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); |
592 | 0 | } |
593 | | |
594 | 0 | void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { |
595 | 0 | if (!Options.SaveArtifacts) |
596 | 0 | return; |
597 | 0 | std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); |
598 | 0 | if (!Options.ExactArtifactPath.empty()) |
599 | 0 | Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. |
600 | 0 | WriteToFile(U, Path); |
601 | 0 | Printf("artifact_prefix='%s'; Test unit written to %s\n", |
602 | 0 | Options.ArtifactPrefix.c_str(), Path.c_str()); |
603 | 0 | if (U.size() <= kMaxUnitSizeToPrint) |
604 | 0 | Printf("Base64: %s\n", Base64(U).c_str()); |
605 | 0 | } |
606 | | |
607 | 0 | void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { |
608 | 0 | if (!Options.PrintNEW) |
609 | 0 | return; |
610 | 0 | PrintStats(Text, ""); |
611 | 0 | if (Options.Verbosity) { |
612 | 0 | Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); |
613 | 0 | MD.PrintMutationSequence(); |
614 | 0 | Printf("\n"); |
615 | 0 | } |
616 | 0 | } |
617 | | |
618 | 0 | void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { |
619 | 0 | II->NumSuccessfullMutations++; |
620 | 0 | MD.RecordSuccessfulMutationSequence(); |
621 | 0 | PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW "); |
622 | 0 | WriteToOutputCorpus(U); |
623 | 0 | NumberOfNewUnitsAdded++; |
624 | 0 | CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. |
625 | 0 | LastCorpusUpdateRun = TotalNumberOfRuns; |
626 | 0 | } |
627 | | |
628 | | // Tries detecting a memory leak on the particular input that we have just |
629 | | // executed before calling this function. |
630 | | void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, |
631 | 16.2k | bool DuringInitialCorpusExecution) { |
632 | 16.2k | if (!HasMoreMallocsThanFrees) |
633 | 16.2k | return; // mallocs==frees, a leak is unlikely. |
634 | 0 | if (!Options.DetectLeaks) |
635 | 0 | return; |
636 | 0 | if (!DuringInitialCorpusExecution && |
637 | 0 | TotalNumberOfRuns >= Options.MaxNumberOfRuns) |
638 | 0 | return; |
639 | 0 | if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || |
640 | 0 | !(EF->__lsan_do_recoverable_leak_check)) |
641 | 0 | return; // No lsan. |
642 | 0 | // Run the target once again, but with lsan disabled so that if there is |
643 | 0 | // a real leak we do not report it twice. |
644 | 0 | EF->__lsan_disable(); |
645 | 0 | ExecuteCallback(Data, Size); |
646 | 0 | EF->__lsan_enable(); |
647 | 0 | if (!HasMoreMallocsThanFrees) |
648 | 0 | return; // a leak is unlikely. |
649 | 0 | if (NumberOfLeakDetectionAttempts++ > 1000) { |
650 | 0 | Options.DetectLeaks = false; |
651 | 0 | Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" |
652 | 0 | " Most likely the target function accumulates allocated\n" |
653 | 0 | " memory in a global state w/o actually leaking it.\n" |
654 | 0 | " You may try running this binary with -trace_malloc=[12]" |
655 | 0 | " to get a trace of mallocs and frees.\n" |
656 | 0 | " If LeakSanitizer is enabled in this process it will still\n" |
657 | 0 | " run on the process shutdown.\n"); |
658 | 0 | return; |
659 | 0 | } |
660 | 0 | // Now perform the actual lsan pass. This is expensive and we must ensure |
661 | 0 | // we don't call it too often. |
662 | 0 | if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. |
663 | 0 | if (DuringInitialCorpusExecution) |
664 | 0 | Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); |
665 | 0 | Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); |
666 | 0 | CurrentUnitSize = Size; |
667 | 0 | DumpCurrentUnit("leak-"); |
668 | 0 | PrintFinalStats(); |
669 | 0 | _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | 0 | void Fuzzer::MutateAndTestOne() { |
674 | 0 | MD.StartMutationSequence(); |
675 | 0 |
|
676 | 0 | auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); |
677 | 0 | const auto &U = II.U; |
678 | 0 | memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); |
679 | 0 | assert(CurrentUnitData); |
680 | 0 | size_t Size = U.size(); |
681 | 0 | assert(Size <= MaxInputLen && "Oversized Unit"); |
682 | 0 | memcpy(CurrentUnitData, U.data(), Size); |
683 | 0 |
|
684 | 0 | assert(MaxMutationLen > 0); |
685 | 0 |
|
686 | 0 | size_t CurrentMaxMutationLen = |
687 | 0 | Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); |
688 | 0 | assert(CurrentMaxMutationLen > 0); |
689 | 0 |
|
690 | 0 | for (int i = 0; i < Options.MutateDepth; i++) { |
691 | 0 | if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) |
692 | 0 | break; |
693 | 0 | MaybeExitGracefully(); |
694 | 0 | size_t NewSize = 0; |
695 | 0 | if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() && |
696 | 0 | Size <= CurrentMaxMutationLen) |
697 | 0 | NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size, |
698 | 0 | II.DataFlowTraceForFocusFunction); |
699 | 0 | else |
700 | 0 | NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); |
701 | 0 | assert(NewSize > 0 && "Mutator returned empty unit"); |
702 | 0 | assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit"); |
703 | 0 | Size = NewSize; |
704 | 0 | II.NumExecutedMutations++; |
705 | 0 |
|
706 | 0 | bool FoundUniqFeatures = false; |
707 | 0 | bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II, |
708 | 0 | &FoundUniqFeatures); |
709 | 0 | TryDetectingAMemoryLeak(CurrentUnitData, Size, |
710 | 0 | /*DuringInitialCorpusExecution*/ false); |
711 | 0 | if (NewCov) { |
712 | 0 | ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); |
713 | 0 | break; // We will mutate this input more in the next rounds. |
714 | 0 | } |
715 | 0 | if (Options.ReduceDepth && !FoundUniqFeatures) |
716 | 0 | break; |
717 | 0 | } |
718 | 0 | } |
719 | | |
720 | 0 | void Fuzzer::PurgeAllocator() { |
721 | 0 | if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator) |
722 | 0 | return; |
723 | 0 | if (duration_cast<seconds>(system_clock::now() - |
724 | 0 | LastAllocatorPurgeAttemptTime) |
725 | 0 | .count() < Options.PurgeAllocatorIntervalSec) |
726 | 0 | return; |
727 | 0 | |
728 | 0 | if (Options.RssLimitMb <= 0 || |
729 | 0 | GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2) |
730 | 0 | EF->__sanitizer_purge_allocator(); |
731 | 0 |
|
732 | 0 | LastAllocatorPurgeAttemptTime = system_clock::now(); |
733 | 0 | } |
734 | | |
735 | 3 | void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) { |
736 | 3 | const size_t kMaxSaneLen = 1 << 20; |
737 | 3 | const size_t kMinDefaultLen = 4096; |
738 | 3 | Vector<SizedFile> SizedFiles; |
739 | 3 | size_t MaxSize = 0; |
740 | 3 | size_t MinSize = -1; |
741 | 3 | size_t TotalSize = 0; |
742 | 3 | size_t LastNumFiles = 0; |
743 | 3 | for (auto &Dir : CorpusDirs) { |
744 | 3 | GetSizedFilesFromDir(Dir, &SizedFiles); |
745 | 3 | Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles, |
746 | 3 | Dir.c_str()); |
747 | 3 | LastNumFiles = SizedFiles.size(); |
748 | 3 | } |
749 | 16.2k | for (auto &File : SizedFiles) { |
750 | 16.2k | MaxSize = Max(File.Size, MaxSize); |
751 | 16.2k | MinSize = Min(File.Size, MinSize); |
752 | 16.2k | TotalSize += File.Size; |
753 | 16.2k | } |
754 | 3 | if (Options.MaxLen == 0) |
755 | 3 | SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen)); |
756 | 3 | assert(MaxInputLen > 0); |
757 | 3 | |
758 | 3 | // Test the callback with empty input and never try it again. |
759 | 3 | uint8_t dummy = 0; |
760 | 3 | ExecuteCallback(&dummy, 0); |
761 | 3 | |
762 | 3 | if (SizedFiles.empty()) { |
763 | 0 | Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); |
764 | 0 | Unit U({'\n'}); // Valid ASCII input. |
765 | 0 | RunOne(U.data(), U.size()); |
766 | 3 | } else { |
767 | 3 | Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb" |
768 | 3 | " rss: %zdMb\n", |
769 | 3 | SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb()); |
770 | 3 | if (Options.ShuffleAtStartUp) |
771 | 3 | std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand()); |
772 | 3 | |
773 | 3 | if (Options.PreferSmall) { |
774 | 3 | std::stable_sort(SizedFiles.begin(), SizedFiles.end()); |
775 | 3 | assert(SizedFiles.front().Size <= SizedFiles.back().Size); |
776 | 3 | } |
777 | 3 | |
778 | 3 | // Load and execute inputs one by one. |
779 | 16.2k | for (auto &SF : SizedFiles) { |
780 | 16.2k | auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false); |
781 | 16.2k | assert(U.size() <= MaxInputLen); |
782 | 16.2k | RunOne(U.data(), U.size()); |
783 | 16.2k | CheckExitOnSrcPosOrItem(); |
784 | 16.2k | TryDetectingAMemoryLeak(U.data(), U.size(), |
785 | 16.2k | /*DuringInitialCorpusExecution*/ true); |
786 | 16.2k | } |
787 | 3 | } |
788 | 3 | |
789 | 3 | PrintStats("INITED"); |
790 | 3 | if (!Options.FocusFunction.empty()) |
791 | 0 | Printf("INFO: %zd/%zd inputs touch the focus function\n", |
792 | 0 | Corpus.NumInputsThatTouchFocusFunction(), Corpus.size()); |
793 | 3 | if (!Options.DataFlowTrace.empty()) |
794 | 0 | Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n", |
795 | 0 | Corpus.NumInputsWithDataFlowTrace(), Corpus.size()); |
796 | 3 | |
797 | 3 | if (Corpus.empty() && Options.MaxNumberOfRuns) { |
798 | 0 | Printf("ERROR: no interesting inputs were found. " |
799 | 0 | "Is the code instrumented for coverage? Exiting.\n"); |
800 | 0 | exit(1); |
801 | 0 | } |
802 | 3 | } |
803 | | |
804 | 3 | void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) { |
805 | 3 | ReadAndExecuteSeedCorpora(CorpusDirs); |
806 | 3 | DFT.Clear(); // No need for DFT any more. |
807 | 3 | TPC.SetPrintNewPCs(Options.PrintNewCovPcs); |
808 | 3 | TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs); |
809 | 3 | system_clock::time_point LastCorpusReload = system_clock::now(); |
810 | 3 | if (Options.DoCrossOver) |
811 | 3 | MD.SetCorpus(&Corpus); |
812 | 3 | while (true) { |
813 | 3 | auto Now = system_clock::now(); |
814 | 3 | if (duration_cast<seconds>(Now - LastCorpusReload).count() >= |
815 | 3 | Options.ReloadIntervalSec) { |
816 | 0 | RereadOutputCorpus(MaxInputLen); |
817 | 0 | LastCorpusReload = system_clock::now(); |
818 | 0 | } |
819 | 3 | if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) |
820 | 3 | break; |
821 | 0 | if (TimedOut()) |
822 | 0 | break; |
823 | 0 | |
824 | 0 | // Update TmpMaxMutationLen |
825 | 0 | if (Options.LenControl) { |
826 | 0 | if (TmpMaxMutationLen < MaxMutationLen && |
827 | 0 | TotalNumberOfRuns - LastCorpusUpdateRun > |
828 | 0 | Options.LenControl * Log(TmpMaxMutationLen)) { |
829 | 0 | TmpMaxMutationLen = |
830 | 0 | Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen)); |
831 | 0 | LastCorpusUpdateRun = TotalNumberOfRuns; |
832 | 0 | } |
833 | 0 | } else { |
834 | 0 | TmpMaxMutationLen = MaxMutationLen; |
835 | 0 | } |
836 | 0 |
|
837 | 0 | // Perform several mutations and runs. |
838 | 0 | MutateAndTestOne(); |
839 | 0 |
|
840 | 0 | PurgeAllocator(); |
841 | 0 | } |
842 | 3 | |
843 | 3 | PrintStats("DONE ", "\n"); |
844 | 3 | MD.PrintRecommendedDictionary(); |
845 | 3 | } |
846 | | |
847 | 0 | void Fuzzer::MinimizeCrashLoop(const Unit &U) { |
848 | 0 | if (U.size() <= 1) |
849 | 0 | return; |
850 | 0 | while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { |
851 | 0 | MD.StartMutationSequence(); |
852 | 0 | memcpy(CurrentUnitData, U.data(), U.size()); |
853 | 0 | for (int i = 0; i < Options.MutateDepth; i++) { |
854 | 0 | size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); |
855 | 0 | assert(NewSize > 0 && NewSize <= MaxMutationLen); |
856 | 0 | ExecuteCallback(CurrentUnitData, NewSize); |
857 | 0 | PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); |
858 | 0 | TryDetectingAMemoryLeak(CurrentUnitData, NewSize, |
859 | 0 | /*DuringInitialCorpusExecution*/ false); |
860 | 0 | } |
861 | 0 | } |
862 | 0 | } |
863 | | |
864 | 0 | void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { |
865 | 0 | if (SMR.IsServer()) { |
866 | 0 | SMR.WriteByteArray(Data, Size); |
867 | 0 | } else if (SMR.IsClient()) { |
868 | 0 | SMR.PostClient(); |
869 | 0 | SMR.WaitServer(); |
870 | 0 | size_t OtherSize = SMR.ReadByteArraySize(); |
871 | 0 | uint8_t *OtherData = SMR.GetByteArray(); |
872 | 0 | if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) { |
873 | 0 | size_t i = 0; |
874 | 0 | for (i = 0; i < Min(Size, OtherSize); i++) |
875 | 0 | if (Data[i] != OtherData[i]) |
876 | 0 | break; |
877 | 0 | Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " |
878 | 0 | "offset %zd\n", |
879 | 0 | GetPid(), Size, OtherSize, i); |
880 | 0 | DumpCurrentUnit("mismatch-"); |
881 | 0 | Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); |
882 | 0 | PrintFinalStats(); |
883 | 0 | _Exit(Options.ErrorExitCode); |
884 | 0 | } |
885 | 0 | } |
886 | 0 | } |
887 | | |
888 | | } // namespace fuzzer |
889 | | |
890 | | extern "C" { |
891 | | |
892 | | __attribute__((visibility("default"))) size_t |
893 | 0 | LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { |
894 | 0 | assert(fuzzer::F); |
895 | 0 | return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); |
896 | 0 | } |
897 | | |
898 | | // Experimental |
899 | | __attribute__((visibility("default"))) void |
900 | 0 | LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { |
901 | 0 | assert(fuzzer::F); |
902 | 0 | fuzzer::F->AnnounceOutput(Data, Size); |
903 | 0 | } |
904 | | } // extern "C" |