Skip to content

Commit 243006d

Browse files
author
kcc
committed
[libFuzzer] extend the -fork=1 functionality. Still not fully usable, but good enough for the first unit test
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer@353775 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 9e8035d commit 243006d

11 files changed

+108
-35
lines changed

FuzzerDriver.cpp

+48-18
Original file line numberDiff line numberDiff line change
@@ -472,46 +472,76 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
472472
}
473473

474474
// This is just a skeleton of an experimental -fork=1 feature.
475-
void FuzzWithFork(const FuzzingOptions &Options,
475+
void FuzzWithFork(Fuzzer *F, const FuzzingOptions &Options,
476476
const Vector<std::string> &Args,
477477
const Vector<std::string> &Corpora) {
478478
Printf("INFO: -fork=1: doing fuzzing in a separate process in order to "
479479
"be more resistant to crashes, timeouts, and OOMs\n");
480+
auto Rand = F->GetMD().GetRand();
480481

481482
Vector<SizedFile> Corpus;
482483
for (auto &Dir : Corpora)
483484
GetSizedFilesFromDir(Dir, &Corpus);
484485
std::sort(Corpus.begin(), Corpus.end());
486+
auto CFPath = TempPath(".fork");
485487

486488
Vector<std::string> Files;
487489
Set<uint32_t> Features;
488490
if (!Corpus.empty()) {
489-
auto CFPath = TempPath(".fork");
490491
CrashResistantMerge(Args, {}, Corpus, &Files, {}, &Features, CFPath);
491492
RemoveFile(CFPath);
492493
}
493-
Printf("INFO: -fork=1: %zd seeds, starting to fuzz\n", Files.size());
494+
auto TempDir = TempPath("Dir");
495+
MkDir(TempDir);
496+
Printf("INFO: -fork=1: %zd seeds, starting to fuzz; scratch: %s\n",
497+
Files.size(), TempDir.c_str());
494498

495-
Command Cmd(Args);
496-
Cmd.removeFlag("fork");
499+
Command BaseCmd(Args);
500+
BaseCmd.removeFlag("fork");
497501
for (auto &C : Corpora) // Remove all corpora from the args.
498-
Cmd.removeArgument(C);
499-
if (Files.size() >= 2)
500-
Cmd.addFlag("seed_inputs",
501-
Files.back() + "," + Files[Files.size() - 2]);
502-
Cmd.addFlag("runs", "1000000");
503-
Cmd.addFlag("max_total_time", "30");
504-
for (size_t i = 0; i < 1000; i++) {
502+
BaseCmd.removeArgument(C);
503+
BaseCmd.addFlag("runs", "1000000");
504+
BaseCmd.addFlag("max_total_time", "30");
505+
BaseCmd.addArgument(TempDir);
506+
int ExitCode = 0;
507+
for (size_t i = 0; i < 1000000; i++) {
508+
// TODO: take new files from disk e.g. those generated by another process.
509+
Command Cmd(BaseCmd);
510+
if (Files.size() >= 2)
511+
Cmd.addFlag("seed_inputs",
512+
Files[Rand.SkewTowardsLast(Files.size())] + "," +
513+
Files[Rand.SkewTowardsLast(Files.size())]);
505514
Printf("RUN %s\n", Cmd.toString().c_str());
506-
int ExitCode = ExecuteCommand(Cmd);
515+
RmFilesInDir(TempDir);
516+
ExitCode = ExecuteCommand(Cmd);
517+
Printf("Exit code: %d\n", ExitCode);
507518
if (ExitCode == Options.InterruptExitCode)
508-
exit(0);
509-
if (ExitCode == Options.TimeoutExitCode || ExitCode == Options.OOMExitCode)
510-
continue;
519+
break;
520+
Vector<SizedFile> TempFiles;
521+
Vector<std::string>FilesToAdd;
522+
Set<uint32_t> NewFeatures;
523+
GetSizedFilesFromDir(TempDir, &TempFiles);
524+
CrashResistantMerge(Args, {}, TempFiles, &FilesToAdd, Features,
525+
&NewFeatures, CFPath);
526+
RemoveFile(CFPath);
527+
for (auto &Path : FilesToAdd) {
528+
auto NewPath = F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen));
529+
if (!NewPath.empty())
530+
Files.push_back(NewPath);
531+
}
532+
Features.insert(NewFeatures.begin(), NewFeatures.end());
533+
Printf("INFO: temp_files: %zd files_added: %zd newft: %zd ft: %zd\n",
534+
TempFiles.size(), FilesToAdd.size(), NewFeatures.size(),
535+
Features.size());
511536
if (ExitCode != 0) break;
512537
}
513538

514-
exit(0);
539+
RmFilesInDir(TempDir);
540+
RmDir(TempDir);
541+
542+
// Use the exit code from the last child process.
543+
Printf("Fork: exiting: %d\n", ExitCode);
544+
exit(ExitCode);
515545
}
516546

517547
void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector<std::string> &Args,
@@ -770,7 +800,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
770800
}
771801

772802
if (Flags.fork)
773-
FuzzWithFork(Options, Args, *Inputs);
803+
FuzzWithFork(F, Options, Args, *Inputs);
774804

775805
if (Flags.merge)
776806
Merge(F, Options, Args, *Inputs, Flags.merge_control_file);

FuzzerFlags.def

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ FUZZER_FLAG_INT(
3636
"If one unit runs more than this number of seconds the process will abort.")
3737
FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug "
3838
"this exit code will be used.")
39-
FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout "
39+
FUZZER_FLAG_INT(timeout_exitcode, 70, "When libFuzzer reports a timeout "
4040
"this exit code will be used.")
4141
FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
4242
"time in seconds to run the fuzzer.")

FuzzerIO.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,11 @@ void Printf(const char *Fmt, ...) {
125125
fflush(OutputFile);
126126
}
127127

128+
void RmFilesInDir(const std::string &Path) {
129+
Vector<std::string> Files;
130+
ListFilesInDirRecursive(Path, 0, &Files, /*TopDir*/true);
131+
for (auto &F : Files)
132+
RemoveFile(F);
133+
}
134+
128135
} // namespace fuzzer

FuzzerIO.h

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ void DiscardOutput(int Fd);
8181

8282
intptr_t GetHandleFromFd(int fd);
8383

84+
void MkDir(const std::string &Path);
85+
void RmDir(const std::string &Path);
86+
void RmFilesInDir(const std::string &Path);
87+
8488
} // namespace fuzzer
8589

8690
#endif // LLVM_FUZZER_IO_H

FuzzerIOPosix.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,18 @@ bool IsInterestingCoverageFile(const std::string &FileName) {
136136
return true;
137137
}
138138

139-
140139
void RawPrint(const char *Str) {
141140
write(2, Str, strlen(Str));
142141
}
143142

143+
void MkDir(const std::string &Path) {
144+
mkdir(Path.c_str(), 0700);
145+
}
146+
147+
void RmDir(const std::string &Path) {
148+
rmdir(Path.c_str());
149+
}
150+
144151
} // namespace fuzzer
145152

146153
#endif // LIBFUZZER_POSIX

FuzzerIOWindows.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ void RawPrint(const char *Str) {
336336
_write(2, Str, strlen(Str));
337337
}
338338

339+
void MkDir(const std::string &Path) {
340+
Printf("MkDir: unimplemented\n");
341+
}
342+
343+
void RmDir(const std::string &Path) {
344+
Printf("RmDir: unimplemented\n");
345+
}
346+
339347
} // namespace fuzzer
340348

341349
#endif // LIBFUZZER_WINDOWS

FuzzerInternal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class Fuzzer {
8787

8888
void HandleMalloc(size_t Size);
8989
static void MaybeExitGracefully();
90-
void WriteToOutputCorpus(const Unit &U);
90+
std::string WriteToOutputCorpus(const Unit &U);
9191

9292
private:
9393
void AlarmCallback();

FuzzerLoop.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -537,15 +537,16 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
537537
delete[] DataCopy;
538538
}
539539

540-
void Fuzzer::WriteToOutputCorpus(const Unit &U) {
540+
std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
541541
if (Options.OnlyASCII)
542542
assert(IsASCII(U));
543543
if (Options.OutputCorpus.empty())
544-
return;
544+
return "";
545545
std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
546546
WriteToFile(U, Path);
547547
if (Options.Verbosity >= 2)
548548
Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
549+
return Path;
549550
}
550551

551552
void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {

FuzzerMerge.cpp

+16-11
Original file line numberDiff line numberDiff line change
@@ -120,28 +120,28 @@ size_t Merger::ApproximateMemoryConsumption() const {
120120
return Res;
121121
}
122122

123-
// Decides which files need to be merged (add thost to NewFiles).
123+
// Decides which files need to be merged (add those to NewFiles).
124124
// Returns the number of new features added.
125125
size_t Merger::Merge(const Set<uint32_t> &InitialFeatures,
126-
Set<uint32_t> *AllFeatures,
126+
Set<uint32_t> *NewFeatures,
127127
Vector<std::string> *NewFiles) {
128128
NewFiles->clear();
129129
assert(NumFilesInFirstCorpus <= Files.size());
130-
*AllFeatures = InitialFeatures;
130+
Set<uint32_t> AllFeatures = InitialFeatures;
131131

132132
// What features are in the initial corpus?
133133
for (size_t i = 0; i < NumFilesInFirstCorpus; i++) {
134134
auto &Cur = Files[i].Features;
135-
AllFeatures->insert(Cur.begin(), Cur.end());
135+
AllFeatures.insert(Cur.begin(), Cur.end());
136136
}
137-
size_t InitialNumFeatures = AllFeatures->size();
137+
size_t InitialNumFeatures = AllFeatures.size();
138138

139139
// Remove all features that we already know from all other inputs.
140140
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
141141
auto &Cur = Files[i].Features;
142142
Vector<uint32_t> Tmp;
143-
std::set_difference(Cur.begin(), Cur.end(), AllFeatures->begin(),
144-
AllFeatures->end(), std::inserter(Tmp, Tmp.begin()));
143+
std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
144+
AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
145145
Cur.swap(Tmp);
146146
}
147147

@@ -161,12 +161,17 @@ size_t Merger::Merge(const Set<uint32_t> &InitialFeatures,
161161
auto &Cur = Files[i].Features;
162162
// Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(),
163163
// Files[i].Size, Cur.size());
164-
size_t OldSize = AllFeatures->size();
165-
AllFeatures->insert(Cur.begin(), Cur.end());
166-
if (AllFeatures->size() > OldSize)
164+
bool FoundNewFeatures = false;
165+
for (auto Fe: Cur) {
166+
if (AllFeatures.insert(Fe).second) {
167+
FoundNewFeatures = true;
168+
NewFeatures->insert(Fe);
169+
}
170+
}
171+
if (FoundNewFeatures)
167172
NewFiles->push_back(Files[i].Name);
168173
}
169-
return AllFeatures->size() - InitialNumFeatures;
174+
return AllFeatures.size() - InitialNumFeatures;
170175
}
171176

172177
Set<uint32_t> Merger::AllFeatures() const {

FuzzerRandom.h

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ class Random : public std::mt19937 {
2020
result_type operator()() { return this->std::mt19937::operator()(); }
2121
size_t Rand() { return this->operator()(); }
2222
size_t RandBool() { return Rand() % 2; }
23+
size_t SkewTowardsLast(size_t n) {
24+
size_t T = this->operator()(n * n);
25+
size_t Res = sqrt(T);
26+
return Res;
27+
}
2328
size_t operator()(size_t n) { return n ? Rand() % n : 0; }
2429
intptr_t operator()(intptr_t From, intptr_t To) {
2530
assert(From < To);

FuzzerUtilLinux.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@
1313
#include "FuzzerCommand.h"
1414

1515
#include <stdlib.h>
16+
#include <sys/types.h>
17+
#include <sys/wait.h>
18+
1619

1720
namespace fuzzer {
1821

1922
int ExecuteCommand(const Command &Cmd) {
2023
std::string CmdLine = Cmd.toString();
21-
return system(CmdLine.c_str());
24+
int exit_code = system(CmdLine.c_str());
25+
if (WIFEXITED(exit_code))
26+
return WEXITSTATUS(exit_code);
27+
return exit_code;
2228
}
2329

2430
} // namespace fuzzer

0 commit comments

Comments
 (0)