File: | projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp |
Warning: | line 37, column 5 Null pointer passed as an argument to a 'nonnull' parameter |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===// | |||
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 | // FuzzerDriver and flag parsing. | |||
10 | //===----------------------------------------------------------------------===// | |||
11 | ||||
12 | #include "FuzzerCommand.h" | |||
13 | #include "FuzzerCorpus.h" | |||
14 | #include "FuzzerIO.h" | |||
15 | #include "FuzzerInterface.h" | |||
16 | #include "FuzzerInternal.h" | |||
17 | #include "FuzzerMutate.h" | |||
18 | #include "FuzzerRandom.h" | |||
19 | #include "FuzzerShmem.h" | |||
20 | #include "FuzzerTracePC.h" | |||
21 | #include <algorithm> | |||
22 | #include <atomic> | |||
23 | #include <chrono> | |||
24 | #include <cstdlib> | |||
25 | #include <cstring> | |||
26 | #include <mutex> | |||
27 | #include <string> | |||
28 | #include <thread> | |||
29 | ||||
30 | // This function should be present in the libFuzzer so that the client | |||
31 | // binary can test for its existence. | |||
32 | extern "C" __attribute__((used)) void __libfuzzer_is_present() {} | |||
33 | ||||
34 | namespace fuzzer { | |||
35 | ||||
36 | // Program arguments. | |||
37 | struct FlagDescription { | |||
38 | const char *Name; | |||
39 | const char *Description; | |||
40 | int Default; | |||
41 | int *IntFlag; | |||
42 | const char **StrFlag; | |||
43 | unsigned int *UIntFlag; | |||
44 | }; | |||
45 | ||||
46 | struct { | |||
47 | #define FUZZER_DEPRECATED_FLAG(Name) | |||
48 | #define FUZZER_FLAG_INT(Name, Default, Description) int Name; | |||
49 | #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; | |||
50 | #define FUZZER_FLAG_STRING(Name, Description) const char *Name; | |||
51 | #include "FuzzerFlags.def" | |||
52 | #undef FUZZER_DEPRECATED_FLAG | |||
53 | #undef FUZZER_FLAG_INT | |||
54 | #undef FUZZER_FLAG_UNSIGNED | |||
55 | #undef FUZZER_FLAG_STRING | |||
56 | } Flags; | |||
57 | ||||
58 | static const FlagDescription FlagDescriptions [] { | |||
59 | #define FUZZER_DEPRECATED_FLAG(Name) \ | |||
60 | {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, | |||
61 | #define FUZZER_FLAG_INT(Name, Default, Description) \ | |||
62 | {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, | |||
63 | #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ | |||
64 | {#Name, Description, static_cast<int>(Default), \ | |||
65 | nullptr, nullptr, &Flags.Name}, | |||
66 | #define FUZZER_FLAG_STRING(Name, Description) \ | |||
67 | {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, | |||
68 | #include "FuzzerFlags.def" | |||
69 | #undef FUZZER_DEPRECATED_FLAG | |||
70 | #undef FUZZER_FLAG_INT | |||
71 | #undef FUZZER_FLAG_UNSIGNED | |||
72 | #undef FUZZER_FLAG_STRING | |||
73 | }; | |||
74 | ||||
75 | static const size_t kNumFlags = | |||
76 | sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); | |||
77 | ||||
78 | static Vector<std::string> *Inputs; | |||
79 | static std::string *ProgName; | |||
80 | ||||
81 | static void PrintHelp() { | |||
82 | Printf("Usage:\n"); | |||
83 | auto Prog = ProgName->c_str(); | |||
84 | Printf("\nTo run fuzzing pass 0 or more directories.\n"); | |||
85 | Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); | |||
86 | ||||
87 | Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); | |||
88 | Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); | |||
89 | ||||
90 | Printf("\nFlags: (strictly in form -flag=value)\n"); | |||
91 | size_t MaxFlagLen = 0; | |||
92 | for (size_t F = 0; F < kNumFlags; F++) | |||
93 | MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); | |||
94 | ||||
95 | for (size_t F = 0; F < kNumFlags; F++) { | |||
96 | const auto &D = FlagDescriptions[F]; | |||
97 | if (strstr(D.Description, "internal flag") == D.Description) continue; | |||
98 | Printf(" %s", D.Name); | |||
99 | for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) | |||
100 | Printf(" "); | |||
101 | Printf("\t"); | |||
102 | Printf("%d\t%s\n", D.Default, D.Description); | |||
103 | } | |||
104 | Printf("\nFlags starting with '--' will be ignored and " | |||
105 | "will be passed verbatim to subprocesses.\n"); | |||
106 | } | |||
107 | ||||
108 | static const char *FlagValue(const char *Param, const char *Name) { | |||
109 | size_t Len = strlen(Name); | |||
110 | if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && | |||
111 | Param[Len + 1] == '=') | |||
112 | return &Param[Len + 2]; | |||
113 | return nullptr; | |||
114 | } | |||
115 | ||||
116 | // Avoid calling stol as it triggers a bug in clang/glibc build. | |||
117 | static long MyStol(const char *Str) { | |||
118 | long Res = 0; | |||
119 | long Sign = 1; | |||
120 | if (*Str == '-') { | |||
121 | Str++; | |||
122 | Sign = -1; | |||
123 | } | |||
124 | for (size_t i = 0; Str[i]; i++) { | |||
125 | char Ch = Str[i]; | |||
126 | if (Ch < '0' || Ch > '9') | |||
127 | return Res; | |||
128 | Res = Res * 10 + (Ch - '0'); | |||
129 | } | |||
130 | return Res * Sign; | |||
131 | } | |||
132 | ||||
133 | static bool ParseOneFlag(const char *Param) { | |||
134 | if (Param[0] != '-') return false; | |||
135 | if (Param[1] == '-') { | |||
136 | static bool PrintedWarning = false; | |||
137 | if (!PrintedWarning) { | |||
138 | PrintedWarning = true; | |||
139 | Printf("INFO: libFuzzer ignores flags that start with '--'\n"); | |||
140 | } | |||
141 | for (size_t F = 0; F < kNumFlags; F++) | |||
142 | if (FlagValue(Param + 1, FlagDescriptions[F].Name)) | |||
143 | Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); | |||
144 | return true; | |||
145 | } | |||
146 | for (size_t F = 0; F < kNumFlags; F++) { | |||
147 | const char *Name = FlagDescriptions[F].Name; | |||
148 | const char *Str = FlagValue(Param, Name); | |||
149 | if (Str) { | |||
150 | if (FlagDescriptions[F].IntFlag) { | |||
151 | int Val = MyStol(Str); | |||
152 | *FlagDescriptions[F].IntFlag = Val; | |||
153 | if (Flags.verbosity >= 2) | |||
154 | Printf("Flag: %s %d\n", Name, Val); | |||
155 | return true; | |||
156 | } else if (FlagDescriptions[F].UIntFlag) { | |||
157 | unsigned int Val = std::stoul(Str); | |||
158 | *FlagDescriptions[F].UIntFlag = Val; | |||
159 | if (Flags.verbosity >= 2) | |||
160 | Printf("Flag: %s %u\n", Name, Val); | |||
161 | return true; | |||
162 | } else if (FlagDescriptions[F].StrFlag) { | |||
163 | *FlagDescriptions[F].StrFlag = Str; | |||
164 | if (Flags.verbosity >= 2) | |||
165 | Printf("Flag: %s %s\n", Name, Str); | |||
166 | return true; | |||
167 | } else { // Deprecated flag. | |||
168 | Printf("Flag: %s: deprecated, don't use\n", Name); | |||
169 | return true; | |||
170 | } | |||
171 | } | |||
172 | } | |||
173 | Printf("\n\nWARNING: unrecognized flag '%s'; " | |||
174 | "use -help=1 to list all flags\n\n", Param); | |||
175 | return true; | |||
176 | } | |||
177 | ||||
178 | // We don't use any library to minimize dependencies. | |||
179 | static void ParseFlags(const Vector<std::string> &Args) { | |||
180 | for (size_t F = 0; F < kNumFlags; F++) { | |||
181 | if (FlagDescriptions[F].IntFlag) | |||
182 | *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; | |||
183 | if (FlagDescriptions[F].UIntFlag) | |||
184 | *FlagDescriptions[F].UIntFlag = | |||
185 | static_cast<unsigned int>(FlagDescriptions[F].Default); | |||
186 | if (FlagDescriptions[F].StrFlag) | |||
187 | *FlagDescriptions[F].StrFlag = nullptr; | |||
188 | } | |||
189 | Inputs = new Vector<std::string>; | |||
190 | for (size_t A = 1; A < Args.size(); A++) { | |||
191 | if (ParseOneFlag(Args[A].c_str())) { | |||
192 | if (Flags.ignore_remaining_args) | |||
193 | break; | |||
194 | continue; | |||
195 | } | |||
196 | Inputs->push_back(Args[A]); | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | static std::mutex Mu; | |||
201 | ||||
202 | static void PulseThread() { | |||
203 | while (true) { | |||
204 | SleepSeconds(600); | |||
205 | std::lock_guard<std::mutex> Lock(Mu); | |||
206 | Printf("pulse...\n"); | |||
207 | } | |||
208 | } | |||
209 | ||||
210 | static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter, | |||
211 | unsigned NumJobs, std::atomic<bool> *HasErrors) { | |||
212 | while (true) { | |||
213 | unsigned C = (*Counter)++; | |||
214 | if (C >= NumJobs) break; | |||
215 | std::string Log = "fuzz-" + std::to_string(C) + ".log"; | |||
216 | Command Cmd(BaseCmd); | |||
217 | Cmd.setOutputFile(Log); | |||
218 | Cmd.combineOutAndErr(); | |||
219 | if (Flags.verbosity) { | |||
220 | std::string CommandLine = Cmd.toString(); | |||
221 | Printf("%s\n", CommandLine.c_str()); | |||
222 | } | |||
223 | int ExitCode = ExecuteCommand(Cmd); | |||
224 | if (ExitCode != 0) | |||
225 | *HasErrors = true; | |||
226 | std::lock_guard<std::mutex> Lock(Mu); | |||
227 | Printf("================== Job %u exited with exit code %d ============\n", | |||
228 | C, ExitCode); | |||
229 | fuzzer::CopyFileToErr(Log); | |||
230 | } | |||
231 | } | |||
232 | ||||
233 | std::string CloneArgsWithoutX(const Vector<std::string> &Args, | |||
234 | const char *X1, const char *X2) { | |||
235 | std::string Cmd; | |||
236 | for (auto &S : Args) { | |||
237 | if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2)) | |||
238 | continue; | |||
239 | Cmd += S + " "; | |||
240 | } | |||
241 | return Cmd; | |||
242 | } | |||
243 | ||||
244 | static int RunInMultipleProcesses(const Vector<std::string> &Args, | |||
245 | unsigned NumWorkers, unsigned NumJobs) { | |||
246 | std::atomic<unsigned> Counter(0); | |||
247 | std::atomic<bool> HasErrors(false); | |||
248 | Command Cmd(Args); | |||
249 | Cmd.removeFlag("jobs"); | |||
250 | Cmd.removeFlag("workers"); | |||
251 | Vector<std::thread> V; | |||
252 | std::thread Pulse(PulseThread); | |||
253 | Pulse.detach(); | |||
254 | for (unsigned i = 0; i < NumWorkers; i++) | |||
255 | V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors)); | |||
256 | for (auto &T : V) | |||
257 | T.join(); | |||
258 | return HasErrors ? 1 : 0; | |||
259 | } | |||
260 | ||||
261 | static void RssThread(Fuzzer *F, size_t RssLimitMb) { | |||
262 | while (true) { | |||
263 | SleepSeconds(1); | |||
264 | size_t Peak = GetPeakRSSMb(); | |||
265 | if (Peak > RssLimitMb) | |||
266 | F->RssLimitCallback(); | |||
267 | } | |||
268 | } | |||
269 | ||||
270 | static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { | |||
271 | if (!RssLimitMb) return; | |||
272 | std::thread T(RssThread, F, RssLimitMb); | |||
273 | T.detach(); | |||
274 | } | |||
275 | ||||
276 | int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { | |||
277 | Unit U = FileToVector(InputFilePath); | |||
278 | if (MaxLen && MaxLen < U.size()) | |||
279 | U.resize(MaxLen); | |||
280 | F->ExecuteCallback(U.data(), U.size()); | |||
281 | F->TryDetectingAMemoryLeak(U.data(), U.size(), true); | |||
282 | return 0; | |||
283 | } | |||
284 | ||||
285 | static bool AllInputsAreFiles() { | |||
286 | if (Inputs->empty()) return false; | |||
287 | for (auto &Path : *Inputs) | |||
288 | if (!IsFile(Path)) | |||
289 | return false; | |||
290 | return true; | |||
291 | } | |||
292 | ||||
293 | static std::string GetDedupTokenFromFile(const std::string &Path) { | |||
294 | auto S = FileToString(Path); | |||
295 | auto Beg = S.find("DEDUP_TOKEN:"); | |||
296 | if (Beg == std::string::npos) | |||
297 | return ""; | |||
298 | auto End = S.find('\n', Beg); | |||
299 | if (End == std::string::npos) | |||
300 | return ""; | |||
301 | return S.substr(Beg, End - Beg); | |||
302 | } | |||
303 | ||||
304 | int CleanseCrashInput(const Vector<std::string> &Args, | |||
305 | const FuzzingOptions &Options) { | |||
306 | if (Inputs->size() != 1 || !Flags.exact_artifact_path) { | |||
307 | Printf("ERROR: -cleanse_crash should be given one input file and" | |||
308 | " -exact_artifact_path\n"); | |||
309 | exit(1); | |||
310 | } | |||
311 | std::string InputFilePath = Inputs->at(0); | |||
312 | std::string OutputFilePath = Flags.exact_artifact_path; | |||
313 | Command Cmd(Args); | |||
314 | Cmd.removeFlag("cleanse_crash"); | |||
315 | ||||
316 | assert(Cmd.hasArgument(InputFilePath))(static_cast <bool> (Cmd.hasArgument(InputFilePath)) ? void (0) : __assert_fail ("Cmd.hasArgument(InputFilePath)", "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp" , 316, __extension__ __PRETTY_FUNCTION__)); | |||
317 | Cmd.removeArgument(InputFilePath); | |||
318 | ||||
319 | auto LogFilePath = DirPlusFile( | |||
320 | TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); | |||
321 | auto TmpFilePath = DirPlusFile( | |||
322 | TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro"); | |||
323 | Cmd.addArgument(TmpFilePath); | |||
324 | Cmd.setOutputFile(LogFilePath); | |||
325 | Cmd.combineOutAndErr(); | |||
326 | ||||
327 | std::string CurrentFilePath = InputFilePath; | |||
328 | auto U = FileToVector(CurrentFilePath); | |||
329 | size_t Size = U.size(); | |||
330 | ||||
331 | const Vector<uint8_t> ReplacementBytes = {' ', 0xff}; | |||
332 | for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { | |||
333 | bool Changed = false; | |||
334 | for (size_t Idx = 0; Idx < Size; Idx++) { | |||
335 | Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts, | |||
336 | Idx, Size); | |||
337 | uint8_t OriginalByte = U[Idx]; | |||
338 | if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(), | |||
339 | ReplacementBytes.end(), | |||
340 | OriginalByte)) | |||
341 | continue; | |||
342 | for (auto NewByte : ReplacementBytes) { | |||
343 | U[Idx] = NewByte; | |||
344 | WriteToFile(U, TmpFilePath); | |||
345 | auto ExitCode = ExecuteCommand(Cmd); | |||
346 | RemoveFile(TmpFilePath); | |||
347 | if (!ExitCode) { | |||
348 | U[Idx] = OriginalByte; | |||
349 | } else { | |||
350 | Changed = true; | |||
351 | Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte); | |||
352 | WriteToFile(U, OutputFilePath); | |||
353 | break; | |||
354 | } | |||
355 | } | |||
356 | } | |||
357 | if (!Changed) break; | |||
358 | } | |||
359 | RemoveFile(LogFilePath); | |||
360 | return 0; | |||
361 | } | |||
362 | ||||
363 | int MinimizeCrashInput(const Vector<std::string> &Args, | |||
364 | const FuzzingOptions &Options) { | |||
365 | if (Inputs->size() != 1) { | |||
366 | Printf("ERROR: -minimize_crash should be given one input file\n"); | |||
367 | exit(1); | |||
368 | } | |||
369 | std::string InputFilePath = Inputs->at(0); | |||
370 | Command BaseCmd(Args); | |||
371 | BaseCmd.removeFlag("minimize_crash"); | |||
372 | BaseCmd.removeFlag("exact_artifact_path"); | |||
373 | assert(BaseCmd.hasArgument(InputFilePath))(static_cast <bool> (BaseCmd.hasArgument(InputFilePath) ) ? void (0) : __assert_fail ("BaseCmd.hasArgument(InputFilePath)" , "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp" , 373, __extension__ __PRETTY_FUNCTION__)); | |||
374 | BaseCmd.removeArgument(InputFilePath); | |||
375 | if (Flags.runs <= 0 && Flags.max_total_time == 0) { | |||
376 | Printf("INFO: you need to specify -runs=N or " | |||
377 | "-max_total_time=N with -minimize_crash=1\n" | |||
378 | "INFO: defaulting to -max_total_time=600\n"); | |||
379 | BaseCmd.addFlag("max_total_time", "600"); | |||
380 | } | |||
381 | ||||
382 | auto LogFilePath = DirPlusFile( | |||
383 | TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); | |||
384 | BaseCmd.setOutputFile(LogFilePath); | |||
385 | BaseCmd.combineOutAndErr(); | |||
386 | ||||
387 | std::string CurrentFilePath = InputFilePath; | |||
388 | while (true) { | |||
389 | Unit U = FileToVector(CurrentFilePath); | |||
390 | Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n", | |||
391 | CurrentFilePath.c_str(), U.size()); | |||
392 | ||||
393 | Command Cmd(BaseCmd); | |||
394 | Cmd.addArgument(CurrentFilePath); | |||
395 | ||||
396 | std::string CommandLine = Cmd.toString(); | |||
397 | Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str()); | |||
398 | int ExitCode = ExecuteCommand(Cmd); | |||
399 | if (ExitCode == 0) { | |||
400 | Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str()); | |||
401 | exit(1); | |||
402 | } | |||
403 | Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize " | |||
404 | "it further\n", | |||
405 | CurrentFilePath.c_str(), U.size()); | |||
406 | auto DedupToken1 = GetDedupTokenFromFile(LogFilePath); | |||
407 | if (!DedupToken1.empty()) | |||
408 | Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str()); | |||
409 | ||||
410 | std::string ArtifactPath = | |||
411 | Flags.exact_artifact_path | |||
412 | ? Flags.exact_artifact_path | |||
413 | : Options.ArtifactPrefix + "minimized-from-" + Hash(U); | |||
414 | Cmd.addFlag("minimize_crash_internal_step", "1"); | |||
415 | Cmd.addFlag("exact_artifact_path", ArtifactPath); | |||
416 | CommandLine = Cmd.toString(); | |||
417 | Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str()); | |||
418 | ExitCode = ExecuteCommand(Cmd); | |||
419 | CopyFileToErr(LogFilePath); | |||
420 | if (ExitCode == 0) { | |||
421 | if (Flags.exact_artifact_path) { | |||
422 | CurrentFilePath = Flags.exact_artifact_path; | |||
423 | WriteToFile(U, CurrentFilePath); | |||
424 | } | |||
425 | Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n", | |||
426 | CurrentFilePath.c_str(), U.size()); | |||
427 | break; | |||
428 | } | |||
429 | auto DedupToken2 = GetDedupTokenFromFile(LogFilePath); | |||
430 | if (!DedupToken2.empty()) | |||
431 | Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str()); | |||
432 | ||||
433 | if (DedupToken1 != DedupToken2) { | |||
434 | if (Flags.exact_artifact_path) { | |||
435 | CurrentFilePath = Flags.exact_artifact_path; | |||
436 | WriteToFile(U, CurrentFilePath); | |||
437 | } | |||
438 | Printf("CRASH_MIN: mismatch in dedup tokens" | |||
439 | " (looks like a different bug). Won't minimize further\n"); | |||
440 | break; | |||
441 | } | |||
442 | ||||
443 | CurrentFilePath = ArtifactPath; | |||
444 | Printf("*********************************\n"); | |||
445 | } | |||
446 | RemoveFile(LogFilePath); | |||
447 | return 0; | |||
448 | } | |||
449 | ||||
450 | int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { | |||
451 | assert(Inputs->size() == 1)(static_cast <bool> (Inputs->size() == 1) ? void (0) : __assert_fail ("Inputs->size() == 1", "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp" , 451, __extension__ __PRETTY_FUNCTION__)); | |||
452 | std::string InputFilePath = Inputs->at(0); | |||
453 | Unit U = FileToVector(InputFilePath); | |||
454 | Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); | |||
455 | if (U.size() < 2) { | |||
456 | Printf("INFO: The input is small enough, exiting\n"); | |||
457 | exit(0); | |||
458 | } | |||
459 | F->SetMaxInputLen(U.size()); | |||
460 | F->SetMaxMutationLen(U.size() - 1); | |||
461 | F->MinimizeCrashLoop(U); | |||
462 | Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); | |||
463 | exit(0); | |||
464 | return 0; | |||
465 | } | |||
466 | ||||
467 | int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict, | |||
468 | UnitVector& Corpus) { | |||
469 | Printf("Started dictionary minimization (up to %d tests)\n", | |||
470 | Dict.size() * Corpus.size() * 2); | |||
471 | ||||
472 | // Scores and usage count for each dictionary unit. | |||
473 | Vector<int> Scores(Dict.size()); | |||
474 | Vector<int> Usages(Dict.size()); | |||
475 | ||||
476 | Vector<size_t> InitialFeatures; | |||
477 | Vector<size_t> ModifiedFeatures; | |||
478 | for (auto &C : Corpus) { | |||
479 | // Get coverage for the testcase without modifications. | |||
480 | F->ExecuteCallback(C.data(), C.size()); | |||
481 | InitialFeatures.clear(); | |||
482 | TPC.CollectFeatures([&](size_t Feature) { | |||
483 | InitialFeatures.push_back(Feature); | |||
484 | }); | |||
485 | ||||
486 | for (size_t i = 0; i < Dict.size(); ++i) { | |||
487 | Vector<uint8_t> Data = C; | |||
488 | auto StartPos = std::search(Data.begin(), Data.end(), | |||
489 | Dict[i].begin(), Dict[i].end()); | |||
490 | // Skip dictionary unit, if the testcase does not contain it. | |||
491 | if (StartPos == Data.end()) | |||
492 | continue; | |||
493 | ||||
494 | ++Usages[i]; | |||
495 | while (StartPos != Data.end()) { | |||
496 | // Replace all occurrences of dictionary unit in the testcase. | |||
497 | auto EndPos = StartPos + Dict[i].size(); | |||
498 | for (auto It = StartPos; It != EndPos; ++It) | |||
499 | *It ^= 0xFF; | |||
500 | ||||
501 | StartPos = std::search(EndPos, Data.end(), | |||
502 | Dict[i].begin(), Dict[i].end()); | |||
503 | } | |||
504 | ||||
505 | // Get coverage for testcase with masked occurrences of dictionary unit. | |||
506 | F->ExecuteCallback(Data.data(), Data.size()); | |||
507 | ModifiedFeatures.clear(); | |||
508 | TPC.CollectFeatures([&](size_t Feature) { | |||
509 | ModifiedFeatures.push_back(Feature); | |||
510 | }); | |||
511 | ||||
512 | if (InitialFeatures == ModifiedFeatures) | |||
513 | --Scores[i]; | |||
514 | else | |||
515 | Scores[i] += 2; | |||
516 | } | |||
517 | } | |||
518 | ||||
519 | Printf("###### Useless dictionary elements. ######\n"); | |||
520 | for (size_t i = 0; i < Dict.size(); ++i) { | |||
521 | // Dictionary units with positive score are treated as useful ones. | |||
522 | if (Scores[i] > 0) | |||
523 | continue; | |||
524 | ||||
525 | Printf("\""); | |||
526 | PrintASCII(Dict[i].data(), Dict[i].size(), "\""); | |||
527 | Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]); | |||
528 | } | |||
529 | Printf("###### End of useless dictionary elements. ######\n"); | |||
530 | return 0; | |||
531 | } | |||
532 | ||||
533 | int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { | |||
534 | using namespace fuzzer; | |||
535 | assert(argc && argv && "Argument pointers cannot be nullptr")(static_cast <bool> (argc && argv && "Argument pointers cannot be nullptr" ) ? void (0) : __assert_fail ("argc && argv && \"Argument pointers cannot be nullptr\"" , "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp" , 535, __extension__ __PRETTY_FUNCTION__)); | |||
536 | std::string Argv0((*argv)[0]); | |||
537 | EF = new ExternalFunctions(); | |||
538 | if (EF->LLVMFuzzerInitialize) | |||
| ||||
539 | EF->LLVMFuzzerInitialize(argc, argv); | |||
540 | const Vector<std::string> Args(*argv, *argv + *argc); | |||
541 | assert(!Args.empty())(static_cast <bool> (!Args.empty()) ? void (0) : __assert_fail ("!Args.empty()", "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp" , 541, __extension__ __PRETTY_FUNCTION__)); | |||
542 | ProgName = new std::string(Args[0]); | |||
543 | if (Argv0 != *ProgName) { | |||
544 | Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n"); | |||
545 | exit(1); | |||
546 | } | |||
547 | ParseFlags(Args); | |||
548 | if (Flags.help) { | |||
549 | PrintHelp(); | |||
550 | return 0; | |||
551 | } | |||
552 | ||||
553 | if (Flags.close_fd_mask & 2) | |||
554 | DupAndCloseStderr(); | |||
555 | if (Flags.close_fd_mask & 1) | |||
556 | CloseStdout(); | |||
557 | ||||
558 | if (Flags.jobs > 0 && Flags.workers == 0) { | |||
559 | Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); | |||
560 | if (Flags.workers > 1) | |||
561 | Printf("Running %u workers\n", Flags.workers); | |||
562 | } | |||
563 | ||||
564 | if (Flags.workers > 0 && Flags.jobs > 0) | |||
565 | return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); | |||
566 | ||||
567 | FuzzingOptions Options; | |||
568 | Options.Verbosity = Flags.verbosity; | |||
569 | Options.MaxLen = Flags.max_len; | |||
570 | Options.LenControl = Flags.len_control; | |||
571 | Options.UnitTimeoutSec = Flags.timeout; | |||
572 | Options.ErrorExitCode = Flags.error_exitcode; | |||
573 | Options.TimeoutExitCode = Flags.timeout_exitcode; | |||
574 | Options.MaxTotalTimeSec = Flags.max_total_time; | |||
575 | Options.DoCrossOver = Flags.cross_over; | |||
576 | Options.MutateDepth = Flags.mutate_depth; | |||
577 | Options.ReduceDepth = Flags.reduce_depth; | |||
578 | Options.UseCounters = Flags.use_counters; | |||
579 | Options.UseMemmem = Flags.use_memmem; | |||
580 | Options.UseCmp = Flags.use_cmp; | |||
581 | Options.UseValueProfile = Flags.use_value_profile; | |||
582 | Options.Shrink = Flags.shrink; | |||
583 | Options.ReduceInputs = Flags.reduce_inputs; | |||
584 | Options.ShuffleAtStartUp = Flags.shuffle; | |||
585 | Options.PreferSmall = Flags.prefer_small; | |||
586 | Options.ReloadIntervalSec = Flags.reload; | |||
587 | Options.OnlyASCII = Flags.only_ascii; | |||
588 | Options.DetectLeaks = Flags.detect_leaks; | |||
589 | Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval; | |||
590 | Options.TraceMalloc = Flags.trace_malloc; | |||
591 | Options.RssLimitMb = Flags.rss_limit_mb; | |||
592 | Options.MallocLimitMb = Flags.malloc_limit_mb; | |||
593 | if (!Options.MallocLimitMb) | |||
594 | Options.MallocLimitMb = Options.RssLimitMb; | |||
595 | if (Flags.runs >= 0) | |||
596 | Options.MaxNumberOfRuns = Flags.runs; | |||
597 | if (!Inputs->empty() && !Flags.minimize_crash_internal_step) | |||
598 | Options.OutputCorpus = (*Inputs)[0]; | |||
599 | Options.ReportSlowUnits = Flags.report_slow_units; | |||
600 | if (Flags.artifact_prefix) | |||
601 | Options.ArtifactPrefix = Flags.artifact_prefix; | |||
602 | if (Flags.exact_artifact_path) | |||
603 | Options.ExactArtifactPath = Flags.exact_artifact_path; | |||
604 | Vector<Unit> Dictionary; | |||
605 | if (Flags.dict) | |||
606 | if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) | |||
607 | return 1; | |||
608 | if (Flags.verbosity > 0 && !Dictionary.empty()) | |||
609 | Printf("Dictionary: %zd entries\n", Dictionary.size()); | |||
610 | bool DoPlainRun = AllInputsAreFiles(); | |||
611 | Options.SaveArtifacts = | |||
612 | !DoPlainRun || Flags.minimize_crash_internal_step; | |||
613 | Options.PrintNewCovPcs = Flags.print_pcs; | |||
614 | Options.PrintNewCovFuncs = Flags.print_funcs; | |||
615 | Options.PrintFinalStats = Flags.print_final_stats; | |||
616 | Options.PrintCorpusStats = Flags.print_corpus_stats; | |||
617 | Options.PrintCoverage = Flags.print_coverage; | |||
618 | Options.DumpCoverage = Flags.dump_coverage; | |||
619 | Options.UseClangCoverage = Flags.use_clang_coverage; | |||
620 | Options.UseFeatureFrequency = Flags.use_feature_frequency; | |||
621 | if (Flags.exit_on_src_pos) | |||
622 | Options.ExitOnSrcPos = Flags.exit_on_src_pos; | |||
623 | if (Flags.exit_on_item) | |||
624 | Options.ExitOnItem = Flags.exit_on_item; | |||
625 | ||||
626 | unsigned Seed = Flags.seed; | |||
627 | // Initialize Seed. | |||
628 | if (Seed == 0) | |||
629 | Seed = | |||
630 | std::chrono::system_clock::now().time_since_epoch().count() + GetPid(); | |||
631 | if (Flags.verbosity) | |||
632 | Printf("INFO: Seed: %u\n", Seed); | |||
633 | ||||
634 | Random Rand(Seed); | |||
635 | auto *MD = new MutationDispatcher(Rand, Options); | |||
636 | auto *Corpus = new InputCorpus(Options.OutputCorpus); | |||
637 | auto *F = new Fuzzer(Callback, *Corpus, *MD, Options); | |||
638 | ||||
639 | for (auto &U: Dictionary) | |||
640 | if (U.size() <= Word::GetMaxSize()) | |||
641 | MD->AddWordToManualDictionary(Word(U.data(), U.size())); | |||
642 | ||||
643 | StartRssThread(F, Flags.rss_limit_mb); | |||
644 | ||||
645 | Options.HandleAbrt = Flags.handle_abrt; | |||
646 | Options.HandleBus = Flags.handle_bus; | |||
647 | Options.HandleFpe = Flags.handle_fpe; | |||
648 | Options.HandleIll = Flags.handle_ill; | |||
649 | Options.HandleInt = Flags.handle_int; | |||
650 | Options.HandleSegv = Flags.handle_segv; | |||
651 | Options.HandleTerm = Flags.handle_term; | |||
652 | Options.HandleXfsz = Flags.handle_xfsz; | |||
653 | Options.HandleUsr1 = Flags.handle_usr1; | |||
654 | Options.HandleUsr2 = Flags.handle_usr2; | |||
655 | SetSignalHandler(Options); | |||
656 | ||||
657 | std::atexit(Fuzzer::StaticExitCallback); | |||
658 | ||||
659 | if (Flags.minimize_crash) | |||
660 | return MinimizeCrashInput(Args, Options); | |||
661 | ||||
662 | if (Flags.minimize_crash_internal_step) | |||
663 | return MinimizeCrashInputInternalStep(F, Corpus); | |||
664 | ||||
665 | if (Flags.cleanse_crash) | |||
666 | return CleanseCrashInput(Args, Options); | |||
667 | ||||
668 | if (auto Name = Flags.run_equivalence_server) { | |||
669 | SMR.Destroy(Name); | |||
670 | if (!SMR.Create(Name)) { | |||
671 | Printf("ERROR: can't create shared memory region\n"); | |||
672 | return 1; | |||
673 | } | |||
674 | Printf("INFO: EQUIVALENCE SERVER UP\n"); | |||
675 | while (true) { | |||
676 | SMR.WaitClient(); | |||
677 | size_t Size = SMR.ReadByteArraySize(); | |||
678 | SMR.WriteByteArray(nullptr, 0); | |||
679 | const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size); | |||
680 | F->ExecuteCallback(tmp.data(), tmp.size()); | |||
681 | SMR.PostServer(); | |||
682 | } | |||
683 | return 0; | |||
684 | } | |||
685 | ||||
686 | if (auto Name = Flags.use_equivalence_server) { | |||
687 | if (!SMR.Open(Name)) { | |||
688 | Printf("ERROR: can't open shared memory region\n"); | |||
689 | return 1; | |||
690 | } | |||
691 | Printf("INFO: EQUIVALENCE CLIENT UP\n"); | |||
692 | } | |||
693 | ||||
694 | if (DoPlainRun) { | |||
695 | Options.SaveArtifacts = false; | |||
696 | int Runs = std::max(1, Flags.runs); | |||
697 | Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), | |||
698 | Inputs->size(), Runs); | |||
699 | for (auto &Path : *Inputs) { | |||
700 | auto StartTime = system_clock::now(); | |||
701 | Printf("Running: %s\n", Path.c_str()); | |||
702 | for (int Iter = 0; Iter < Runs; Iter++) | |||
703 | RunOneTest(F, Path.c_str(), Options.MaxLen); | |||
704 | auto StopTime = system_clock::now(); | |||
705 | auto MS = duration_cast<milliseconds>(StopTime - StartTime).count(); | |||
706 | Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); | |||
707 | } | |||
708 | Printf("***\n" | |||
709 | "*** NOTE: fuzzing was not performed, you have only\n" | |||
710 | "*** executed the target code on a fixed set of inputs.\n" | |||
711 | "***\n"); | |||
712 | F->PrintFinalStats(); | |||
713 | exit(0); | |||
714 | } | |||
715 | ||||
716 | if (Flags.merge) { | |||
717 | F->CrashResistantMerge(Args, *Inputs, | |||
718 | Flags.load_coverage_summary, | |||
719 | Flags.save_coverage_summary, | |||
720 | Flags.merge_control_file); | |||
721 | exit(0); | |||
722 | } | |||
723 | ||||
724 | if (Flags.merge_inner) { | |||
725 | const size_t kDefaultMaxMergeLen = 1 << 20; | |||
726 | if (Options.MaxLen == 0) | |||
727 | F->SetMaxInputLen(kDefaultMaxMergeLen); | |||
728 | assert(Flags.merge_control_file)(static_cast <bool> (Flags.merge_control_file) ? void ( 0) : __assert_fail ("Flags.merge_control_file", "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp" , 728, __extension__ __PRETTY_FUNCTION__)); | |||
729 | F->CrashResistantMergeInternalStep(Flags.merge_control_file); | |||
730 | exit(0); | |||
731 | } | |||
732 | ||||
733 | if (Flags.analyze_dict) { | |||
734 | size_t MaxLen = INT_MAX2147483647; // Large max length. | |||
735 | UnitVector InitialCorpus; | |||
736 | for (auto &Inp : *Inputs) { | |||
737 | Printf("Loading corpus dir: %s\n", Inp.c_str()); | |||
738 | ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, | |||
739 | MaxLen, /*ExitOnError=*/false); | |||
740 | } | |||
741 | ||||
742 | if (Dictionary.empty() || Inputs->empty()) { | |||
743 | Printf("ERROR: can't analyze dict without dict and corpus provided\n"); | |||
744 | return 1; | |||
745 | } | |||
746 | if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) { | |||
747 | Printf("Dictionary analysis failed\n"); | |||
748 | exit(1); | |||
749 | } | |||
750 | Printf("Dictionary analysis suceeded\n"); | |||
751 | exit(0); | |||
752 | } | |||
753 | ||||
754 | F->Loop(*Inputs); | |||
755 | ||||
756 | if (Flags.verbosity) | |||
757 | Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(), | |||
758 | F->secondsSinceProcessStartUp()); | |||
759 | F->PrintFinalStats(); | |||
760 | ||||
761 | exit(0); // Don't let F destroy itself. | |||
762 | } | |||
763 | ||||
764 | // Storage for global ExternalFunctions object. | |||
765 | ExternalFunctions *EF = nullptr; | |||
766 | ||||
767 | } // namespace fuzzer |
1 | //===- FuzzerShmem.h - shared memory interface ------------------*- C++ -* ===// | |||
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 | // SharedMemoryRegion | |||
10 | //===----------------------------------------------------------------------===// | |||
11 | ||||
12 | #ifndef LLVM_FUZZER_SHMEM_H | |||
13 | #define LLVM_FUZZER_SHMEM_H | |||
14 | ||||
15 | #include <algorithm> | |||
16 | #include <cstring> | |||
17 | #include <string> | |||
18 | ||||
19 | #include "FuzzerDefs.h" | |||
20 | ||||
21 | namespace fuzzer { | |||
22 | ||||
23 | class SharedMemoryRegion { | |||
24 | public: | |||
25 | bool Create(const char *Name); | |||
26 | bool Open(const char *Name); | |||
27 | bool Destroy(const char *Name); | |||
28 | uint8_t *GetData() { return Data; } | |||
29 | void PostServer() {Post(0);} | |||
30 | void WaitServer() {Wait(0);} | |||
31 | void PostClient() {Post(1);} | |||
32 | void WaitClient() {Wait(1);} | |||
33 | ||||
34 | size_t WriteByteArray(const uint8_t *Bytes, size_t N) { | |||
35 | assert(N <= kShmemSize - sizeof(N))(static_cast <bool> (N <= kShmemSize - sizeof(N)) ? void (0) : __assert_fail ("N <= kShmemSize - sizeof(N)", "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerShmem.h" , 35, __extension__ __PRETTY_FUNCTION__)); | |||
36 | memcpy(GetData(), &N, sizeof(N)); | |||
37 | memcpy(GetData() + sizeof(N), Bytes, N); | |||
| ||||
38 | assert(N == ReadByteArraySize())(static_cast <bool> (N == ReadByteArraySize()) ? void ( 0) : __assert_fail ("N == ReadByteArraySize()", "/build/llvm-toolchain-snapshot-7~svn326551/projects/compiler-rt/lib/fuzzer/FuzzerShmem.h" , 38, __extension__ __PRETTY_FUNCTION__)); | |||
39 | return N; | |||
40 | } | |||
41 | size_t ReadByteArraySize() { | |||
42 | size_t Res; | |||
43 | memcpy(&Res, GetData(), sizeof(Res)); | |||
44 | return Res; | |||
45 | } | |||
46 | uint8_t *GetByteArray() { return GetData() + sizeof(size_t); } | |||
47 | ||||
48 | bool IsServer() const { return Data && IAmServer; } | |||
49 | bool IsClient() const { return Data && !IAmServer; } | |||
50 | ||||
51 | private: | |||
52 | ||||
53 | static const size_t kShmemSize = 1 << 22; | |||
54 | bool IAmServer; | |||
55 | std::string Path(const char *Name); | |||
56 | std::string SemName(const char *Name, int Idx); | |||
57 | void Post(int Idx); | |||
58 | void Wait(int Idx); | |||
59 | ||||
60 | bool Map(int fd); | |||
61 | uint8_t *Data = nullptr; | |||
62 | void *Semaphore[2]; | |||
63 | }; | |||
64 | ||||
65 | extern SharedMemoryRegion SMR; | |||
66 | ||||
67 | } // namespace fuzzer | |||
68 | ||||
69 | #endif // LLVM_FUZZER_SHMEM_H |