summaryrefslogtreecommitdiff
path: root/chromium/third_party/libFuzzer
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-03-08 10:28:10 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-03-20 13:40:30 +0000
commite733310db58160074f574c429d48f8308c0afe17 (patch)
treef8aef4b7e62a69928dbcf880620eece20f98c6df /chromium/third_party/libFuzzer
parent2f583e4aec1ae3a86fa047829c96b310dc12ecdf (diff)
downloadqtwebengine-chromium-e733310db58160074f574c429d48f8308c0afe17.tar.gz
BASELINE: Update Chromium to 56.0.2924.122
Change-Id: I4e04de8f47e47e501c46ed934c76a431c6337ced Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/libFuzzer')
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerCorpus.h155
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerDFSan.h61
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerDefs.h19
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerDictionary.h7
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerDriver.cpp21
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def2
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerFlags.def13
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerIO.cpp14
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerInternal.h34
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerLoop.cpp273
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerMutate.cpp132
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerMutate.h15
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerOptions.h7
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerRandom.h5
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp334
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerTracePC.h96
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp452
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerUtil.cpp11
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h9
-rwxr-xr-xchromium/third_party/libFuzzer/src/build.sh2
-rwxr-xr-xchromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh25
-rw-r--r--chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key10
-rw-r--r--chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem10
-rw-r--r--chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc39
-rwxr-xr-xchromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh5
-rwxr-xr-xchromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh22
-rw-r--r--chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc27
-rwxr-xr-xchromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh10
-rw-r--r--chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c41
29 files changed, 854 insertions, 997 deletions
diff --git a/chromium/third_party/libFuzzer/src/FuzzerCorpus.h b/chromium/third_party/libFuzzer/src/FuzzerCorpus.h
index b9a06655273..355c242e1f4 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerCorpus.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerCorpus.h
@@ -17,43 +17,71 @@
#include "FuzzerDefs.h"
#include "FuzzerRandom.h"
+#include "FuzzerTracePC.h"
namespace fuzzer {
struct InputInfo {
Unit U; // The actual input data.
uint8_t Sha1[kSHA1NumBytes]; // Checksum.
+ // Number of features that this input has and no smaller input has.
+ size_t NumFeatures = 0;
+ size_t Tmp = 0; // Used by ValidateFeatureSet.
// Stats.
- uintptr_t NumExecutedMutations = 0;
- uintptr_t NumSuccessfullMutations = 0;
+ size_t NumExecutedMutations = 0;
+ size_t NumSuccessfullMutations = 0;
+ bool MayDeleteFile = false;
};
class InputCorpus {
public:
- InputCorpus() {
- Inputs.reserve(1 << 14); // Avoid too many resizes.
+ static const size_t kFeatureSetSize = 1 << 16;
+ InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) {
+ memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
+ memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+ }
+ ~InputCorpus() {
+ for (auto II : Inputs)
+ delete II;
}
size_t size() const { return Inputs.size(); }
+ size_t SizeInBytes() const {
+ size_t Res = 0;
+ for (auto II : Inputs)
+ Res += II->U.size();
+ return Res;
+ }
+ size_t NumActiveUnits() const {
+ size_t Res = 0;
+ for (auto II : Inputs)
+ Res += !II->U.empty();
+ return Res;
+ }
bool empty() const { return Inputs.empty(); }
- const Unit &operator[] (size_t Idx) const { return Inputs[Idx].U; }
- void AddToCorpus(const Unit &U) {
+ const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
+ void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile = false) {
+ assert(!U.empty());
uint8_t Hash[kSHA1NumBytes];
+ if (FeatureDebug)
+ Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
ComputeSHA1(U.data(), U.size(), Hash);
- if (!Hashes.insert(Sha1ToString(Hash)).second) return;
- Inputs.push_back(InputInfo());
- InputInfo &II = Inputs.back();
+ Hashes.insert(Sha1ToString(Hash));
+ Inputs.push_back(new InputInfo());
+ InputInfo &II = *Inputs.back();
II.U = U;
+ II.NumFeatures = NumFeatures;
+ II.MayDeleteFile = MayDeleteFile;
memcpy(II.Sha1, Hash, kSHA1NumBytes);
UpdateCorpusDistribution();
+ ValidateFeatureSet();
}
- typedef const std::vector<InputInfo>::const_iterator ConstIter;
- ConstIter begin() const { return Inputs.begin(); }
- ConstIter end() const { return Inputs.end(); }
-
bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
+ bool HasUnit(const std::string &H) { return Hashes.count(H); }
InputInfo &ChooseUnitToMutate(Random &Rand) {
- return Inputs[ChooseUnitIdxToMutate(Rand)];
+ InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
+ assert(!II.U.empty());
+ return II;
};
// Returns an index of random unit from the corpus to mutate.
@@ -67,30 +95,119 @@ class InputCorpus {
void PrintStats() {
for (size_t i = 0; i < Inputs.size(); i++) {
- const auto &II = Inputs[i];
+ const auto &II = *Inputs[i];
Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i,
Sha1ToString(II.Sha1).c_str(), II.U.size(),
II.NumExecutedMutations, II.NumSuccessfullMutations);
}
}
+ void PrintFeatureSet() {
+ for (size_t i = 0; i < kFeatureSetSize; i++) {
+ if(size_t Sz = GetFeature(i))
+ Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz);
+ }
+ Printf("\n\t");
+ for (size_t i = 0; i < Inputs.size(); i++)
+ if (size_t N = Inputs[i]->NumFeatures)
+ Printf(" %zd=>%zd ", i, N);
+ Printf("\n");
+ }
+
+ void DeleteInput(size_t Idx) {
+ InputInfo &II = *Inputs[Idx];
+ if (!OutputCorpus.empty() && II.MayDeleteFile)
+ DeleteFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
+ Unit().swap(II.U);
+ if (FeatureDebug)
+ Printf("EVICTED %zd\n", Idx);
+ }
+
+ bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
+ assert(NewSize);
+ Idx = Idx % kFeatureSetSize;
+ uint32_t OldSize = GetFeature(Idx);
+ if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
+ if (OldSize > 0) {
+ size_t OldIdx = SmallestElementPerFeature[Idx];
+ InputInfo &II = *Inputs[OldIdx];
+ assert(II.NumFeatures > 0);
+ II.NumFeatures--;
+ if (II.NumFeatures == 0)
+ DeleteInput(OldIdx);
+ }
+ if (FeatureDebug)
+ Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
+ SmallestElementPerFeature[Idx] = Inputs.size();
+ InputSizesPerFeature[Idx] = NewSize;
+ CountingFeatures = true;
+ return true;
+ }
+ return false;
+ }
+
+ size_t NumFeatures() const {
+ size_t Res = 0;
+ for (size_t i = 0; i < kFeatureSetSize; i++)
+ Res += GetFeature(i) != 0;
+ return Res;
+ }
+
+ void ResetFeatureSet() {
+ assert(Inputs.empty());
+ memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
+ memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+ }
+
private:
+ static const bool FeatureDebug = false;
+
+ size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
+
+ void ValidateFeatureSet() {
+ if (!CountingFeatures) return;
+ if (FeatureDebug)
+ PrintFeatureSet();
+ for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
+ if (GetFeature(Idx))
+ Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
+ for (auto II: Inputs) {
+ if (II->Tmp != II->NumFeatures)
+ Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
+ assert(II->Tmp == II->NumFeatures);
+ II->Tmp = 0;
+ }
+ }
+
// Updates the probability distribution for the units in the corpus.
// Must be called whenever the corpus or unit weights are changed.
void UpdateCorpusDistribution() {
size_t N = Inputs.size();
- std::vector<double> Intervals(N + 1);
- std::vector<double> Weights(N);
+ Intervals.resize(N + 1);
+ Weights.resize(N);
std::iota(Intervals.begin(), Intervals.end(), 0);
- std::iota(Weights.begin(), Weights.end(), 1);
+ if (CountingFeatures)
+ for (size_t i = 0; i < N; i++)
+ Weights[i] = Inputs[i]->NumFeatures * (i + 1);
+ else
+ std::iota(Weights.begin(), Weights.end(), 1);
CorpusDistribution = std::piecewise_constant_distribution<double>(
Intervals.begin(), Intervals.end(), Weights.begin());
}
std::piecewise_constant_distribution<double> CorpusDistribution;
+ std::vector<double> Intervals;
+ std::vector<double> Weights;
+
std::unordered_set<std::string> Hashes;
- std::vector<InputInfo> Inputs;
+ std::vector<InputInfo*> Inputs;
+
+ bool CountingFeatures = false;
+ uint32_t InputSizesPerFeature[kFeatureSetSize];
+ uint32_t SmallestElementPerFeature[kFeatureSetSize];
+
+ std::string OutputCorpus;
};
} // namespace fuzzer
diff --git a/chromium/third_party/libFuzzer/src/FuzzerDFSan.h b/chromium/third_party/libFuzzer/src/FuzzerDFSan.h
deleted file mode 100644
index eb206ec61ce..00000000000
--- a/chromium/third_party/libFuzzer/src/FuzzerDFSan.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//===- FuzzerDFSan.h - Internal header for the Fuzzer -----------*- C++ -* ===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// DFSan interface.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_DFSAN_H
-#define LLVM_FUZZER_DFSAN_H
-
-#define LLVM_FUZZER_SUPPORTS_DFSAN 0
-#if defined(__has_include)
-# if __has_include(<sanitizer/dfsan_interface.h>)
-# if defined (__linux__)
-# undef LLVM_FUZZER_SUPPORTS_DFSAN
-# define LLVM_FUZZER_SUPPORTS_DFSAN 1
-# include <sanitizer/dfsan_interface.h>
-# endif // __linux__
-# endif
-#endif // defined(__has_include)
-
-#if LLVM_FUZZER_SUPPORTS_DFSAN
-
-extern "C" {
-__attribute__((weak))
-dfsan_label dfsan_create_label(const char *desc, void *userdata);
-__attribute__((weak))
-void dfsan_set_label(dfsan_label label, void *addr, size_t size);
-__attribute__((weak))
-void dfsan_add_label(dfsan_label label, void *addr, size_t size);
-__attribute__((weak))
-const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
-__attribute__((weak))
-dfsan_label dfsan_read_label(const void *addr, size_t size);
-} // extern "C"
-
-namespace fuzzer {
-static bool ReallyHaveDFSan() {
- return &dfsan_create_label != nullptr;
-}
-} // namespace fuzzer
-#else
-// When compiling with a compiler which does not support dfsan,
-// this code is still expected to build (but not necessary work).
-typedef unsigned short dfsan_label;
-struct dfsan_label_info {
- dfsan_label l1, l2;
- const char *desc;
- void *userdata;
-};
-namespace fuzzer {
-static bool ReallyHaveDFSan() { return false; }
-} // namespace fuzzer
-
-#endif
-
-#endif // LLVM_FUZZER_DFSAN_H
diff --git a/chromium/third_party/libFuzzer/src/FuzzerDefs.h b/chromium/third_party/libFuzzer/src/FuzzerDefs.h
index 3fc62da7ae9..287e23c7afd 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerDefs.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerDefs.h
@@ -60,11 +60,13 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
bool IsFile(const std::string &Path);
long GetEpoch(const std::string &Path);
std::string FileToString(const std::string &Path);
-Unit FileToVector(const std::string &Path, size_t MaxSize = 0);
+Unit FileToVector(const std::string &Path, size_t MaxSize = 0,
+ bool ExitOnError = true);
void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
- long *Epoch, size_t MaxSize);
+ long *Epoch, size_t MaxSize, bool ExitOnError);
void WriteToFile(const Unit &U, const std::string &Path);
void CopyFileToErr(const std::string &Path);
+void DeleteFile(const std::string &Path);
// Returns "Dir/FileName" or equivalent for the current OS.
std::string DirPlusFile(const std::string &DirPath,
const std::string &FileName);
@@ -91,6 +93,8 @@ void SetSigIntHandler();
void SetSigTermHandler();
std::string Base64(const Unit &U);
int ExecuteCommand(const std::string &Command);
+bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out);
+
size_t GetPeakRSSMb();
// Private copy of SHA1 implementation.
@@ -109,5 +113,16 @@ int NumberOfCpuCores();
int GetPid();
void SleepSeconds(int Seconds);
+
+struct ScopedDoingMyOwnMemmem {
+ ScopedDoingMyOwnMemmem();
+ ~ScopedDoingMyOwnMemmem();
+};
+
+inline uint8_t Bswap(uint8_t x) { return x; }
+inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
+inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
+inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
+
} // namespace fuzzer
#endif // LLVM_FUZZER_DEFS_H
diff --git a/chromium/third_party/libFuzzer/src/FuzzerDictionary.h b/chromium/third_party/libFuzzer/src/FuzzerDictionary.h
index 821cf9bd001..c009838ced6 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerDictionary.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerDictionary.h
@@ -68,6 +68,13 @@ class DictionaryEntry {
size_t GetUseCount() const { return UseCount; }
size_t GetSuccessCount() const {return SuccessCount; }
+ void Print(const char *PrintAfter = "\n") {
+ PrintASCII(W.data(), W.size());
+ if (HasPositionHint())
+ Printf("@%zd", GetPositionHint());
+ Printf("%s", PrintAfter);
+ }
+
private:
Word W;
size_t PositionHint = std::numeric_limits<size_t>::max();
diff --git a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp
index f2452dc95f2..c506361b48f 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp
@@ -270,6 +270,7 @@ int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
if (MaxLen && MaxLen < U.size())
U.resize(MaxLen);
F->RunOne(U.data(), U.size());
+ F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
return 0;
}
@@ -342,10 +343,10 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
Unit U = FileToVector(InputFilePath);
assert(U.size() > 2);
Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
- Corpus->AddToCorpus(U);
+ Corpus->AddToCorpus(U, 0);
F->SetMaxInputLen(U.size());
F->SetMaxMutationLen(U.size() - 1);
- F->Loop();
+ F->MinimizeCrashLoop(U);
Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
exit(0);
return 0;
@@ -397,13 +398,16 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.UseIndirCalls = Flags.use_indir_calls;
Options.UseMemcmp = Flags.use_memcmp;
Options.UseMemmem = Flags.use_memmem;
+ Options.UseCmp = Flags.use_cmp;
Options.UseValueProfile = Flags.use_value_profile;
+ Options.Shrink = Flags.shrink;
Options.ShuffleAtStartUp = Flags.shuffle;
Options.PreferSmall = Flags.prefer_small;
- Options.Reload = Flags.reload;
+ Options.ReloadIntervalSec = Flags.reload;
Options.OnlyASCII = Flags.only_ascii;
Options.OutputCSV = Flags.output_csv;
Options.DetectLeaks = Flags.detect_leaks;
+ Options.TraceMalloc = Flags.trace_malloc;
Options.RssLimitMb = Flags.rss_limit_mb;
if (Flags.runs >= 0)
Options.MaxNumberOfRuns = Flags.runs;
@@ -427,9 +431,10 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.PrintFinalStats = Flags.print_final_stats;
Options.PrintCorpusStats = Flags.print_corpus_stats;
Options.PrintCoverage = Flags.print_coverage;
- Options.PruneCorpus = Flags.prune_corpus;
if (Flags.exit_on_src_pos)
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
+ if (Flags.exit_on_item)
+ Options.ExitOnItem = Flags.exit_on_item;
unsigned Seed = Flags.seed;
// Initialize Seed.
@@ -441,7 +446,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Random Rand(Seed);
MutationDispatcher MD(Rand, Options);
- InputCorpus Corpus;
+ InputCorpus Corpus(Options.OutputCorpus);
Fuzzer F(Callback, Corpus, MD, Options);
for (auto &U: Dictionary)
@@ -498,7 +503,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
UnitVector InitialCorpus;
for (auto &Inp : *Inputs) {
Printf("Loading corpus dir: %s\n", Inp.c_str());
- ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, TemporaryMaxLen);
+ ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
+ TemporaryMaxLen, /*ExitOnError=*/false);
}
if (Options.MaxLen == 0) {
@@ -509,11 +515,12 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
}
if (InitialCorpus.empty()) {
- InitialCorpus.push_back(Unit());
+ InitialCorpus.push_back(Unit({0}));
if (Options.Verbosity)
Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
}
F.ShuffleAndMinimize(&InitialCorpus);
+ InitialCorpus.clear(); // Don't need this memory any more.
F.Loop();
if (Flags.verbosity)
diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def
index e5cb3a7d9bb..b34670f85b4 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def
+++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def
@@ -29,8 +29,6 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
EXT_FUNC(__lsan_enable, void, (), false);
EXT_FUNC(__lsan_disable, void, (), false);
EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
-EXT_FUNC(__sanitizer_set_coverage_pc_buffer, void, (uintptr_t*, uintptr_t), false);
-EXT_FUNC(__sanitizer_get_coverage_pc_buffer_pos, uintptr_t, (), false);
EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false);
EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
(void (*malloc_hook)(const volatile void *, size_t),
diff --git a/chromium/third_party/libFuzzer/src/FuzzerFlags.def b/chromium/third_party/libFuzzer/src/FuzzerFlags.def
index 1d62e429b30..01f733d5226 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerFlags.def
+++ b/chromium/third_party/libFuzzer/src/FuzzerFlags.def
@@ -49,6 +49,8 @@ FUZZER_FLAG_INT(use_memmem, 1,
"Use hints from intercepting memmem, strstr, etc")
FUZZER_FLAG_INT(use_value_profile, 0,
"Experimental. Use value profile to guide fuzzing.")
+FUZZER_FLAG_INT(use_cmp, 0, "Experimenta. Use CMP traces to guide mutations")
+FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.")
FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
" this number of jobs in separate worker processes"
" with stdout/stderr redirected to fuzz-JOB.log.")
@@ -56,8 +58,8 @@ FUZZER_FLAG_INT(workers, 0,
"Number of simultaneous worker processes to run the jobs."
" If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
FUZZER_FLAG_INT(reload, 1,
- "Reload the main corpus periodically to get new units"
- " discovered by other processes.")
+ "Reload the main corpus every <N> seconds to get new units"
+ " discovered by other processes. If 0, disabled")
FUZZER_FLAG_INT(report_slow_units, 10,
"Report slowest units if they run for more than this number of seconds.")
FUZZER_FLAG_INT(only_ascii, 0,
@@ -90,13 +92,16 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
"Be careful, this will also close e.g. asan's stderr/stdout.")
FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
"try to detect memory leaks during fuzzing (i.e. not only at shut down).")
+FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
+ "If >= 2 will also print stack traces.")
FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
"reaching this limit of RSS memory usage.")
-FUZZER_FLAG_INT(prune_corpus, 1, "Prune corpus items without new coverage when "
- "loading corpus.")
FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
" from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
"Used primarily for testing libFuzzer itself.")
+FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
+ " was added to the corpus. "
+ "Used primarily for testing libFuzzer itself.")
FUZZER_DEPRECATED_FLAG(exit_on_first)
FUZZER_DEPRECATED_FLAG(save_minimized_corpus)
diff --git a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp
index e956b3eb91e..a70af886c2b 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp
@@ -60,9 +60,9 @@ static void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
*Epoch = E;
}
-Unit FileToVector(const std::string &Path, size_t MaxSize) {
+Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
std::ifstream T(Path);
- if (!T) {
+ if (ExitOnError && !T) {
Printf("No such directory: %s; exiting\n", Path.c_str());
exit(1);
}
@@ -78,6 +78,10 @@ Unit FileToVector(const std::string &Path, size_t MaxSize) {
return Res;
}
+void DeleteFile(const std::string &Path) {
+ unlink(Path.c_str());
+}
+
std::string FileToString(const std::string &Path) {
std::ifstream T(Path);
return std::string((std::istreambuf_iterator<char>(T)),
@@ -97,7 +101,7 @@ void WriteToFile(const Unit &U, const std::string &Path) {
}
void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
- long *Epoch, size_t MaxSize) {
+ long *Epoch, size_t MaxSize, bool ExitOnError) {
long E = Epoch ? *Epoch : 0;
std::vector<std::string> Files;
ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
@@ -108,7 +112,9 @@ void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
NumLoaded++;
if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
- V->push_back(FileToVector(X, MaxSize));
+ auto S = FileToVector(X, MaxSize, ExitOnError);
+ if (!S.empty())
+ V->push_back(S);
}
}
diff --git a/chromium/third_party/libFuzzer/src/FuzzerInternal.h b/chromium/third_party/libFuzzer/src/FuzzerInternal.h
index 49f6a6a7cf3..1b491eaafc5 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerInternal.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerInternal.h
@@ -42,17 +42,13 @@ public:
CounterBitmapBits = 0;
CounterBitmap.clear();
VPMap.Reset();
- TPCMap.Reset();
}
- std::string DebugString() const;
-
size_t BlockCoverage;
size_t CallerCalleeCoverage;
// Precalculated number of bits in CounterBitmap.
size_t CounterBitmapBits;
std::vector<uint8_t> CounterBitmap;
- ValueBitMap TPCMap;
ValueBitMap VPMap;
};
@@ -60,15 +56,22 @@ public:
FuzzingOptions Options);
~Fuzzer();
void Loop();
+ void MinimizeCrashLoop(const Unit &U);
void ShuffleAndMinimize(UnitVector *V);
void InitializeTraceState();
- void AssignTaintLabels(uint8_t *Data, size_t Size);
void RereadOutputCorpus(size_t MaxSize);
size_t secondsSinceProcessStartUp() {
return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
.count();
}
+
+ bool TimedOut() {
+ return Options.MaxTotalTimeSec > 0 &&
+ secondsSinceProcessStartUp() >
+ static_cast<size_t>(Options.MaxTotalTimeSec);
+ }
+
size_t execPerSec() {
size_t Seconds = secondsSinceProcessStartUp();
return Seconds ? TotalNumberOfRuns / Seconds : 0;
@@ -81,7 +84,7 @@ public:
static void StaticInterruptCallback();
void ExecuteCallback(const uint8_t *Data, size_t Size);
- bool RunOne(const uint8_t *Data, size_t Size);
+ size_t RunOne(const uint8_t *Data, size_t Size);
// Merge Corpora[1:] into Corpora[0].
void Merge(const std::vector<std::string> &Corpora);
@@ -98,6 +101,8 @@ public:
bool InFuzzingThread() const { return IsMyThread; }
size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const;
+ void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+ bool DuringInitialCorpusExecution);
private:
void AlarmCallback();
@@ -105,20 +110,14 @@ private:
void InterruptCallback();
void MutateAndTestOne();
void ReportNewCoverage(InputInfo *II, const Unit &U);
- void PrintNewPCs();
- void PrintOneNewPC(uintptr_t PC);
- bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
+ size_t RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
void WriteToOutputCorpus(const Unit &U);
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0);
void PrintStatusForNewUnit(const Unit &U);
void ShuffleCorpus(UnitVector *V);
- void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
- bool DuringInitialCorpusExecution);
- void AddToCorpusAndMaybeRerun(const Unit &U);
- void CheckExitOnSrcPos();
-
- bool UpdateMaxCoverage();
+ void AddToCorpus(const Unit &U);
+ void CheckExitOnSrcPosOrItem();
// Trace-based fuzzing: we run a unit with some kind of tracing
// enabled and record potentially useful mutations. Then
@@ -166,11 +165,6 @@ private:
size_t MaxInputLen = 0;
size_t MaxMutationLen = 0;
- // For -print_pcs
- uintptr_t* PcBuffer = nullptr;
- size_t PcBufferLen = 0;
- size_t PcBufferPos = 0, PrevPcBufferPos = 0;
-
// Need to know our own thread.
static thread_local bool IsMyThread;
diff --git a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp
index f7d4e4ef362..0d2a38b6a85 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp
@@ -17,6 +17,7 @@
#include <algorithm>
#include <cstring>
+#include <set>
#include <memory>
#if defined(__has_include)
@@ -63,11 +64,8 @@ void Fuzzer::ResetEdgeCoverage() {
}
void Fuzzer::ResetCounters() {
- if (Options.UseCounters) {
+ if (Options.UseCounters)
EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
- }
- if (EF->__sanitizer_get_coverage_pc_buffer_pos)
- PcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
}
void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) {
@@ -82,8 +80,6 @@ void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) {
bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
bool Res = false;
- TPC.FinalizeTrace();
-
uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
if (NewBlockCoverage > C->BlockCoverage) {
Res = true;
@@ -110,48 +106,52 @@ bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
}
}
- if (TPC.UpdateCounterMap(&C->TPCMap))
- Res = true;
-
- if (TPC.UpdateValueProfileMap(&C->VPMap))
- Res = true;
-
- if (EF->__sanitizer_get_coverage_pc_buffer_pos) {
- uint64_t NewPcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
- if (NewPcBufferPos > PcBufferPos) {
- Res = true;
- PcBufferPos = NewPcBufferPos;
- }
-
- if (PcBufferLen && NewPcBufferPos >= PcBufferLen) {
- Printf("ERROR: PC buffer overflow\n");
- _Exit(1);
- }
- }
-
return Res;
}
// Leak detection is expensive, so we first check if there were more mallocs
// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
struct MallocFreeTracer {
- void Start() {
+ void Start(int TraceLevel) {
+ this->TraceLevel = TraceLevel;
+ if (TraceLevel)
+ Printf("MallocFreeTracer: START\n");
Mallocs = 0;
Frees = 0;
}
// Returns true if there were more mallocs than frees.
- bool Stop() { return Mallocs > Frees; }
+ bool Stop() {
+ if (TraceLevel)
+ Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
+ Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
+ bool Result = Mallocs > Frees;
+ Mallocs = 0;
+ Frees = 0;
+ TraceLevel = 0;
+ return Result;
+ }
std::atomic<size_t> Mallocs;
std::atomic<size_t> Frees;
+ int TraceLevel = 0;
};
static MallocFreeTracer AllocTracer;
void MallocHook(const volatile void *ptr, size_t size) {
- AllocTracer.Mallocs++;
+ size_t N = AllocTracer.Mallocs++;
+ if (int TraceLevel = AllocTracer.TraceLevel) {
+ Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
+ if (TraceLevel >= 2 && EF)
+ EF->__sanitizer_print_stack_trace();
+ }
}
void FreeHook(const volatile void *ptr) {
- AllocTracer.Frees++;
+ size_t N = AllocTracer.Frees++;
+ if (int TraceLevel = AllocTracer.TraceLevel) {
+ Printf("FREE[%zd] %p\n", N, ptr);
+ if (TraceLevel >= 2 && EF)
+ EF->__sanitizer_print_stack_trace();
+ }
}
Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
@@ -161,24 +161,18 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
InitializeTraceState();
assert(!F);
F = this;
- TPC.ResetTotalPCCoverage();
TPC.ResetMaps();
- TPC.ResetGuards();
ResetCoverage();
IsMyThread = true;
if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
TPC.SetUseCounters(Options.UseCounters);
TPC.SetUseValueProfile(Options.UseValueProfile);
+ TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
- if (Options.PrintNewCovPcs) {
- PcBufferLen = 1 << 24;
- PcBuffer = new uintptr_t[PcBufferLen];
- EF->__sanitizer_set_coverage_pc_buffer(PcBuffer, PcBufferLen);
- }
if (Options.Verbosity)
TPC.PrintModuleInfo();
- if (!Options.OutputCorpus.empty() && Options.Reload)
+ if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
MaxInputLen = MaxMutationLen = Options.MaxLen;
AllocateCurrentUnitData();
@@ -303,7 +297,7 @@ void Fuzzer::RssLimitCallback() {
GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
if (EF->__sanitizer_print_memory_profile)
- EF->__sanitizer_print_memory_profile(50);
+ EF->__sanitizer_print_memory_profile(95);
DumpCurrentUnit("oom-");
Printf("SUMMARY: libFuzzer: out-of-memory\n");
PrintFinalStats();
@@ -328,21 +322,32 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
Printf("#%zd\t%s", TotalNumberOfRuns, Where);
if (MaxCoverage.BlockCoverage)
Printf(" cov: %zd", MaxCoverage.BlockCoverage);
+ if (size_t N = MaxCoverage.VPMap.GetNumBitsSinceLastMerge())
+ Printf(" vp: %zd", N);
if (size_t N = TPC.GetTotalPCCoverage())
Printf(" cov: %zd", N);
- if (MaxCoverage.VPMap.GetNumBitsSinceLastMerge())
- Printf(" vp: %zd", MaxCoverage.VPMap.GetNumBitsSinceLastMerge());
if (auto TB = MaxCoverage.CounterBitmapBits)
Printf(" bits: %zd", TB);
- if (auto TB = MaxCoverage.TPCMap.GetNumBitsSinceLastMerge())
- Printf(" bits: %zd", MaxCoverage.TPCMap.GetNumBitsSinceLastMerge());
+ if (size_t N = Corpus.NumFeatures())
+ Printf( " ft: %zd", N);
if (MaxCoverage.CallerCalleeCoverage)
Printf(" indir: %zd", MaxCoverage.CallerCalleeCoverage);
- if (size_t N = Corpus.size())
- Printf(" units: %zd", N);
+ if (!Corpus.empty()) {
+ Printf(" corp: %zd", Corpus.NumActiveUnits());
+ if (size_t N = Corpus.SizeInBytes()) {
+ if (N < (1<<14))
+ Printf("/%zdb", N);
+ else if (N < (1 << 24))
+ Printf("/%zdKb", N >> 10);
+ else
+ Printf("/%zdMb", N >> 20);
+ }
+ }
if (Units)
Printf(" units: %zd", Units);
+
Printf(" exec/s: %zd", ExecPerSec);
+ Printf(" rss: %zdMb", GetPeakRSSMb());
Printf("%s", End);
}
@@ -374,52 +379,52 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
this->MaxMutationLen = MaxMutationLen;
}
-void Fuzzer::CheckExitOnSrcPos() {
+void Fuzzer::CheckExitOnSrcPosOrItem() {
if (!Options.ExitOnSrcPos.empty()) {
- uintptr_t *PCIDs;
- if (size_t NumNewPCIDs = TPC.GetNewPCIDs(&PCIDs)) {
- for (size_t i = 0; i < NumNewPCIDs; i++) {
- std::string Descr = DescribePC("%L", TPC.GetPCbyPCID(PCIDs[i]));
- if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
- Printf("INFO: found line matching '%s', exiting.\n",
- Options.ExitOnSrcPos.c_str());
- _Exit(0);
- }
+ static auto *PCsSet = new std::set<uintptr_t>;
+ for (size_t i = 1, N = TPC.GetNumPCs(); i < N; i++) {
+ uintptr_t PC = TPC.GetPC(i);
+ if (!PC) continue;
+ if (!PCsSet->insert(PC).second) continue;
+ std::string Descr = DescribePC("%L", PC);
+ if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
+ Printf("INFO: found line matching '%s', exiting.\n",
+ Options.ExitOnSrcPos.c_str());
+ _Exit(0);
}
}
}
-}
-
-void Fuzzer::AddToCorpusAndMaybeRerun(const Unit &U) {
- CheckExitOnSrcPos();
- Corpus.AddToCorpus(U);
- if (TPC.GetTotalPCCoverage()) {
- TPC.ResetMaps();
- TPC.ResetGuards();
- ExecuteCallback(U.data(), U.size());
- TPC.FinalizeTrace();
- TPC.UpdateFeatureSet(Corpus.size() - 1, U.size());
- // TPC.PrintFeatureSet();
+ if (!Options.ExitOnItem.empty()) {
+ if (Corpus.HasUnit(Options.ExitOnItem)) {
+ Printf("INFO: found item with checksum '%s', exiting.\n",
+ Options.ExitOnItem.c_str());
+ _Exit(0);
+ }
}
}
void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
- if (Options.OutputCorpus.empty() || !Options.Reload) return;
+ if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return;
std::vector<Unit> AdditionalCorpus;
ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
- &EpochOfLastReadOfOutputCorpus, MaxSize);
+ &EpochOfLastReadOfOutputCorpus, MaxSize,
+ /*ExitOnError*/ false);
if (Options.Verbosity >= 2)
Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
- for (auto &X : AdditionalCorpus) {
- if (X.size() > MaxSize)
- X.resize(MaxSize);
- if (!Corpus.HasUnit(X)) {
- if (RunOne(X)) {
- AddToCorpusAndMaybeRerun(X);
- PrintStats("RELOAD");
+ bool Reloaded = false;
+ for (auto &U : AdditionalCorpus) {
+ if (U.size() > MaxSize)
+ U.resize(MaxSize);
+ if (!Corpus.HasUnit(U)) {
+ if (size_t NumFeatures = RunOne(U)) {
+ CheckExitOnSrcPosOrItem();
+ Corpus.AddToCorpus(U, NumFeatures);
+ Reloaded = true;
}
}
}
+ if (Reloaded)
+ PrintStats("RELOAD");
}
void Fuzzer::ShuffleCorpus(UnitVector *V) {
@@ -435,10 +440,14 @@ void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) {
if (Options.ShuffleAtStartUp)
ShuffleCorpus(InitialCorpus);
+ // Test the callback with empty input and never try it again.
+ uint8_t dummy;
+ ExecuteCallback(&dummy, 0);
+
for (const auto &U : *InitialCorpus) {
- bool NewCoverage = RunOne(U);
- if (!Options.PruneCorpus || NewCoverage) {
- AddToCorpusAndMaybeRerun(U);
+ if (size_t NumFeatures = RunOne(U)) {
+ CheckExitOnSrcPosOrItem();
+ Corpus.AddToCorpus(U, NumFeatures);
if (Options.Verbosity >= 2)
Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size());
}
@@ -453,18 +462,22 @@ void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) {
}
}
-bool Fuzzer::UpdateMaxCoverage() {
- PrevPcBufferPos = PcBufferPos;
- bool Res = RecordMaxCoverage(&MaxCoverage);
-
- return Res;
-}
-
-bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
+size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
+ if (!Size) return 0;
TotalNumberOfRuns++;
ExecuteCallback(Data, Size);
- bool Res = UpdateMaxCoverage();
+
+ size_t Res = 0;
+ if (size_t NumFeatures = TPC.FinalizeTrace(&Corpus, Size, Options.Shrink))
+ Res = NumFeatures;
+
+ if (!TPC.UsingTracePcGuard()) {
+ if (TPC.UpdateValueProfileMap(&MaxCoverage.VPMap))
+ Res = 1;
+ if (!Res && RecordMaxCoverage(&MaxCoverage))
+ Res = 1;
+ }
auto TimeOfUnit =
duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
@@ -494,13 +507,11 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
memcpy(DataCopy, Data, Size);
if (CurrentUnitData && CurrentUnitData != Data)
memcpy(CurrentUnitData, Data, Size);
- AssignTaintLabels(DataCopy, Size);
CurrentUnitSize = Size;
- AllocTracer.Start();
+ AllocTracer.Start(Options.TraceMalloc);
UnitStartTime = system_clock::now();
ResetCounters(); // Reset coverage right before the callback.
TPC.ResetMaps();
- TPC.ResetGuards();
int Res = CB(DataCopy, Size);
UnitStopTime = system_clock::now();
(void)Res;
@@ -510,16 +521,6 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
delete[] DataCopy;
}
-std::string Fuzzer::Coverage::DebugString() const {
- std::string Result =
- std::string("Coverage{") + "BlockCoverage=" +
- std::to_string(BlockCoverage) + " CallerCalleeCoverage=" +
- std::to_string(CallerCalleeCoverage) + " CounterBitmapBits=" +
- std::to_string(CounterBitmapBits) + " VPMapBits " +
- std::to_string(VPMap.GetNumBitsSinceLastMerge()) + "}";
- return Result;
-}
-
void Fuzzer::WriteToOutputCorpus(const Unit &U) {
if (Options.OnlyASCII)
assert(IsASCII(U));
@@ -555,34 +556,13 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
}
}
-void Fuzzer::PrintOneNewPC(uintptr_t PC) {
- PrintPC("\tNEW_PC: %p %F %L\n",
- "\tNEW_PC: %p\n", PC);
-}
-
-void Fuzzer::PrintNewPCs() {
- if (!Options.PrintNewCovPcs) return;
- if (PrevPcBufferPos != PcBufferPos) {
- int NumPrinted = 0;
- for (size_t I = PrevPcBufferPos; I < PcBufferPos; ++I) {
- if (NumPrinted++ > 30) break; // Don't print too many new PCs.
- PrintOneNewPC(PcBuffer[I]);
- }
- }
- uintptr_t *PCIDs;
- if (size_t NumNewPCIDs = TPC.GetNewPCIDs(&PCIDs))
- for (size_t i = 0; i < NumNewPCIDs; i++)
- PrintOneNewPC(TPC.GetPCbyPCID(PCIDs[i]));
-}
-
void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
II->NumSuccessfullMutations++;
MD.RecordSuccessfulMutationSequence();
PrintStatusForNewUnit(U);
WriteToOutputCorpus(U);
NumberOfNewUnitsAdded++;
- PrintNewPCs();
- AddToCorpusAndMaybeRerun(U);
+ TPC.PrintNewPCs();
}
// Finds minimal number of units in 'Extra' that add coverage to 'Initial'.
@@ -597,16 +577,20 @@ UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial,
for (int Iter = 0; Iter < 10; Iter++) {
ShuffleCorpus(&Res);
TPC.ResetMaps();
- TPC.ResetGuards();
+ Corpus.ResetFeatureSet();
ResetCoverage();
- for (auto &U : Initial)
+ for (auto &U : Initial) {
+ TPC.ResetMaps();
RunOne(U);
+ }
Tmp.clear();
- for (auto &U : Res)
+ for (auto &U : Res) {
+ TPC.ResetMaps();
if (RunOne(U))
Tmp.push_back(U);
+ }
char Stat[7] = "MIN ";
Stat[3] = '0' + Iter;
@@ -633,9 +617,9 @@ void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
assert(MaxInputLen > 0);
UnitVector Initial, Extra;
- ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, MaxInputLen);
+ ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, MaxInputLen, true);
for (auto &C : ExtraCorpora)
- ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, MaxInputLen);
+ ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, MaxInputLen, true);
if (!Initial.empty()) {
Printf("=== Minimizing the initial corpus of %zd units\n", Initial.size());
@@ -663,7 +647,7 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
// Run the target once again, but with lsan disabled so that if there is
// a real leak we do not report it twice.
EF->__lsan_disable();
- RunOne(Data, Size);
+ ExecuteCallback(Data, Size);
EF->__lsan_enable();
if (!HasMoreMallocsThanFrees) return; // a leak is unlikely.
if (NumberOfLeakDetectionAttempts++ > 1000) {
@@ -671,6 +655,8 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
" Most likely the target function accumulates allocated\n"
" memory in a global state w/o actually leaking it.\n"
+ " You may try running this binary with -trace_malloc=[12]"
+ " to get a trace of mallocs and frees.\n"
" If LeakSanitizer is enabled in this process it will still\n"
" run on the process shutdown.\n");
return;
@@ -712,8 +698,12 @@ void Fuzzer::MutateAndTestOne() {
if (i == 0)
StartTraceRecording();
II.NumExecutedMutations++;
- if (RunOne(CurrentUnitData, Size))
+ if (size_t NumFeatures = RunOne(CurrentUnitData, Size)) {
+ Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size}, NumFeatures,
+ /*MayDeleteFile=*/true);
ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
+ CheckExitOnSrcPosOrItem();
+ }
StopTraceRecording();
TryDetectingAMemoryLeak(CurrentUnitData, Size,
/*DuringInitialCorpusExecution*/ false);
@@ -732,16 +722,14 @@ void Fuzzer::Loop() {
MD.SetCorpus(&Corpus);
while (true) {
auto Now = system_clock::now();
- if (duration_cast<seconds>(Now - LastCorpusReload).count()) {
+ if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
+ Options.ReloadIntervalSec) {
RereadOutputCorpus(MaxInputLen);
- LastCorpusReload = Now;
+ LastCorpusReload = system_clock::now();
}
if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
break;
- if (Options.MaxTotalTimeSec > 0 &&
- secondsSinceProcessStartUp() >
- static_cast<size_t>(Options.MaxTotalTimeSec))
- break;
+ if (TimedOut()) break;
// Perform several mutations and runs.
MutateAndTestOne();
}
@@ -750,6 +738,21 @@ void Fuzzer::Loop() {
MD.PrintRecommendedDictionary();
}
+void Fuzzer::MinimizeCrashLoop(const Unit &U) {
+ if (U.size() <= 2) return;
+ while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
+ MD.StartMutationSequence();
+ memcpy(CurrentUnitData, U.data(), U.size());
+ for (int i = 0; i < Options.MutateDepth; i++) {
+ size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
+ assert(NewSize > 0 && NewSize <= MaxMutationLen);
+ RunOne(CurrentUnitData, NewSize);
+ TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
+ /*DuringInitialCorpusExecution*/ false);
+ }
+ }
+}
+
} // namespace fuzzer
extern "C" {
diff --git a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp
index e3b35d4de81..0109f5104fe 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp
@@ -43,12 +43,15 @@ MutationDispatcher::MutationDispatcher(Random &Rand,
{&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
{&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
{&MutationDispatcher::Mutate_AddWordFromManualDictionary,
- "AddFromManualDict"},
+ "ManualDict"},
{&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
- "AddFromTempAutoDict"},
+ "TempAutoDict"},
{&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
- "AddFromPersAutoDict"},
+ "PersAutoDict"},
});
+ if(Options.UseCmp)
+ DefaultMutators.push_back(
+ {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
if (EF->LLVMFuzzerCustomMutator)
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
@@ -171,19 +174,13 @@ size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
}
-size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
- uint8_t *Data, size_t Size, size_t MaxSize) {
- return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
-}
-
-size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
- size_t Size, size_t MaxSize) {
- if (Size > MaxSize) return 0;
- if (D.empty()) return 0;
- DictionaryEntry &DE = D[Rand(D.size())];
+size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ DictionaryEntry &DE) {
const Word &W = DE.GetW();
bool UsePositionHint = DE.HasPositionHint() &&
- DE.GetPositionHint() + W.size() < Size && Rand.RandBool();
+ DE.GetPositionHint() + W.size() < Size &&
+ Rand.RandBool();
if (Rand.RandBool()) { // Insert W.
if (Size + W.size() > MaxSize) return 0;
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
@@ -195,6 +192,84 @@ size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
memcpy(Data + Idx, W.data(), W.size());
}
+ return Size;
+}
+
+// Somewhere in the past we have observed a comparison instructions
+// with arguments Arg1 Arg2. This function tries to guess a dictionary
+// entry that will satisfy that comparison.
+// It first tries to find one of the arguments (possibly swapped) in the
+// input and if it succeeds it creates a DE with a position hint.
+// Otherwise it creates a DE with one of the arguments w/o a position hint.
+template <class T>
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
+ ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
+ bool HandleFirst = Rand.RandBool();
+ T ExistingBytes, DesiredBytes;
+ Word W;
+ const uint8_t *End = Data + Size;
+ for (int Arg = 0; Arg < 2; Arg++) {
+ ExistingBytes = HandleFirst ? Arg1 : Arg2;
+ DesiredBytes = HandleFirst ? Arg2 : Arg1;
+ DesiredBytes += Rand(-1, 1);
+ if (Rand.RandBool()) ExistingBytes = Bswap(ExistingBytes);
+ if (Rand.RandBool()) DesiredBytes = Bswap(DesiredBytes);
+ HandleFirst = !HandleFirst;
+ W.Set(reinterpret_cast<uint8_t*>(&DesiredBytes), sizeof(T));
+ const size_t kMaxNumPositions = 8;
+ size_t Positions[kMaxNumPositions];
+ size_t NumPositions = 0;
+ for (const uint8_t *Cur = Data;
+ Cur < End && NumPositions < kMaxNumPositions; Cur++) {
+ Cur = (uint8_t *)memmem(Cur, End - Cur, &ExistingBytes, sizeof(T));
+ if (!Cur) break;
+ Positions[NumPositions++] = Cur - Data;
+ }
+ if (!NumPositions) break;
+ return DictionaryEntry(W, Positions[Rand(NumPositions)]);
+ }
+ DictionaryEntry DE(W);
+ return DE;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromTORC(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ Word W;
+ DictionaryEntry DE;
+ if (Rand.RandBool()) {
+ auto X = TPC.TORC8.Get(Rand.Rand());
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } else {
+ auto X = TPC.TORC4.Get(Rand.Rand());
+ if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
+ DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data,
+ Size);
+ else
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ }
+ Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+ if (!Size) return 0;
+ DictionaryEntry &DERef =
+ CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
+ kCmpDictionaryEntriesDequeSize];
+ DERef = DE;
+ CurrentDictionaryEntrySequence.push_back(&DERef);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
+ size_t Size, size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ if (D.empty()) return 0;
+ DictionaryEntry &DE = D[Rand(D.size())];
+ Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+ if (!Size) return 0;
DE.IncUseCount();
CurrentDictionaryEntrySequence.push_back(&DE);
return Size;
@@ -284,26 +359,27 @@ size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
return Size;
}
-uint8_t Bswap(uint8_t x) { return x; }
-uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
-uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
-uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
-
template<class T>
size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
if (Size < sizeof(T)) return 0;
size_t Off = Rand(Size - sizeof(T) + 1);
assert(Off + sizeof(T) <= Size);
T Val;
- memcpy(&Val, Data + Off, sizeof(Val));
- T Add = Rand(21);
- Add -= 10;
- if (Rand.RandBool())
- Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
- else
- Val = Val + Add; // Add assuming current endiannes.
- if (Add == 0 || Rand.RandBool()) // Maybe negate.
- Val = -Val;
+ if (Off < 64 && !Rand(4)) {
+ Val = Size;
+ if (Rand.RandBool())
+ Val = Bswap(Val);
+ } else {
+ memcpy(&Val, Data + Off, sizeof(Val));
+ T Add = Rand(21);
+ Add -= 10;
+ if (Rand.RandBool())
+ Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
+ else
+ Val = Val + Add; // Add assuming current endiannes.
+ if (Add == 0 || Rand.RandBool()) // Maybe negate.
+ Val = -Val;
+ }
memcpy(Data + Off, &Val, sizeof(Val));
return Size;
}
diff --git a/chromium/third_party/libFuzzer/src/FuzzerMutate.h b/chromium/third_party/libFuzzer/src/FuzzerMutate.h
index f8611a77124..d3c0b001246 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerMutate.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerMutate.h
@@ -55,6 +55,9 @@ public:
size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
+ /// Mutates data by adding a word from the TORC.
+ size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
+
/// Mutates data by adding a word from the persistent automatic dictionary.
size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
@@ -104,6 +107,12 @@ private:
size_t ToSize, size_t MaxToSize);
size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
size_t ToSize);
+ size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
+ DictionaryEntry &DE);
+
+ template <class T>
+ DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
+ const uint8_t *Data, size_t Size);
Random &Rand;
const FuzzingOptions &Options;
@@ -116,8 +125,14 @@ private:
// Persistent dictionary modified by the fuzzer, consists of
// entries that led to successfull discoveries in the past mutations.
Dictionary PersistentAutoDictionary;
+
std::vector<Mutator> CurrentMutatorSequence;
std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
+
+ static const size_t kCmpDictionaryEntriesDequeSize = 16;
+ DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
+ size_t CmpDictionaryEntriesDequeIdx = 0;
+
const InputCorpus *Corpus = nullptr;
std::vector<uint8_t> MutateInPlaceHere;
diff --git a/chromium/third_party/libFuzzer/src/FuzzerOptions.h b/chromium/third_party/libFuzzer/src/FuzzerOptions.h
index 56c35aa5253..59126a231e3 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerOptions.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerOptions.h
@@ -30,8 +30,10 @@ struct FuzzingOptions {
bool UseIndirCalls = true;
bool UseMemcmp = true;
bool UseMemmem = true;
+ bool UseCmp = false;
bool UseValueProfile = false;
- bool Reload = true;
+ bool Shrink = false;
+ int ReloadIntervalSec = 1;
bool ShuffleAtStartUp = true;
bool PreferSmall = true;
size_t MaxNumberOfRuns = -1L;
@@ -41,6 +43,7 @@ struct FuzzingOptions {
std::string ArtifactPrefix = "./";
std::string ExactArtifactPath;
std::string ExitOnSrcPos;
+ std::string ExitOnItem;
bool SaveArtifacts = true;
bool PrintNEW = true; // Print a status line when new units are found;
bool OutputCSV = false;
@@ -49,7 +52,7 @@ struct FuzzingOptions {
bool PrintCorpusStats = false;
bool PrintCoverage = false;
bool DetectLeaks = true;
- bool PruneCorpus = true;
+ int TraceMalloc = 0;
};
} // namespace fuzzer
diff --git a/chromium/third_party/libFuzzer/src/FuzzerRandom.h b/chromium/third_party/libFuzzer/src/FuzzerRandom.h
index c7714181571..b1be0bb935f 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerRandom.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerRandom.h
@@ -21,6 +21,11 @@ class Random {
size_t Rand() { return R(); }
size_t RandBool() { return Rand() % 2; }
size_t operator()(size_t n) { return n ? Rand() % n : 0; }
+ intptr_t operator()(intptr_t From, intptr_t To) {
+ assert(From < To);
+ intptr_t RangeSize = To - From + 1;
+ return operator()(RangeSize) + From;
+ }
std::mt19937 &Get_mt19937() { return R; }
private:
std::mt19937 R;
diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp
index 9789d5df852..e61d5e0cdb6 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp
@@ -12,7 +12,14 @@
//
//===----------------------------------------------------------------------===//
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "FuzzerCorpus.h"
#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerExtFunctions.h"
#include "FuzzerTracePC.h"
#include "FuzzerValueBitMap.h"
@@ -20,33 +27,25 @@ namespace fuzzer {
TracePC TPC;
-void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) {
- uintptr_t Idx = *Guard;
+void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) {
+ uint32_t Idx = *Guard;
if (!Idx) return;
- uint8_t *CounterPtr = &Counters[Idx % kNumCounters];
- uint8_t Counter = *CounterPtr;
- if (Counter == 0) {
- if (!PCs[Idx]) {
- AddNewPCID(Idx);
- TotalPCCoverage++;
- PCs[Idx] = PC;
- }
- }
- if (UseCounters) {
- if (Counter < 128)
- *CounterPtr = Counter + 1;
- else
- *Guard = 0;
- } else {
- *CounterPtr = 1;
- *Guard = 0;
- }
+ PCs[Idx % kNumPCs] = PC;
+ Counters[Idx % kNumCounters]++;
+}
+
+size_t TracePC::GetTotalPCCoverage() {
+ size_t Res = 0;
+ for (size_t i = 1; i < GetNumPCs(); i++)
+ if (PCs[i])
+ Res++;
+ return Res;
}
-void TracePC::HandleInit(uintptr_t *Start, uintptr_t *Stop) {
+void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
if (Start == Stop || *Start) return;
assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
- for (uintptr_t *P = Start; P < Stop; P++)
+ for (uint32_t *P = Start; P < Stop; P++)
*P = ++NumGuards;
Modules[NumModules].Start = Start;
Modules[NumModules].Stop = Stop;
@@ -60,91 +59,227 @@ void TracePC::PrintModuleInfo() {
Printf("\n");
}
-void TracePC::ResetGuards() {
- uintptr_t N = 0;
- for (size_t M = 0; M < NumModules; M++)
- for (uintptr_t *X = Modules[M].Start; X < Modules[M].Stop; X++)
- *X = ++N;
- assert(N == NumGuards);
-}
-
-void TracePC::FinalizeTrace() {
- if (TotalPCCoverage) {
- const size_t Step = 8;
- assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
- size_t N = Min(kNumCounters, NumGuards + 1);
- N = (N + Step - 1) & ~(Step - 1); // Round up.
- for (size_t Idx = 0; Idx < N; Idx += Step) {
- uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]);
- if (!Bundle) continue;
- for (size_t i = Idx; i < Idx + Step; i++) {
- uint8_t Counter = (Bundle >> (i * 8)) & 0xff;
- if (!Counter) continue;
- Counters[i] = 0;
- unsigned Bit = 0;
- /**/ if (Counter >= 128) Bit = 7;
- else if (Counter >= 32) Bit = 6;
- else if (Counter >= 16) Bit = 5;
- else if (Counter >= 8) Bit = 4;
- else if (Counter >= 4) Bit = 3;
- else if (Counter >= 3) Bit = 2;
- else if (Counter >= 2) Bit = 1;
- CounterMap.AddValue(i * 8 + Bit);
- }
+size_t TracePC::FinalizeTrace(InputCorpus *C, size_t InputSize, bool Shrink) {
+ if (!UsingTracePcGuard()) return 0;
+ size_t Res = 0;
+ const size_t Step = 8;
+ assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
+ size_t N = Min(kNumCounters, NumGuards + 1);
+ N = (N + Step - 1) & ~(Step - 1); // Round up.
+ for (size_t Idx = 0; Idx < N; Idx += Step) {
+ uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]);
+ if (!Bundle) continue;
+ for (size_t i = Idx; i < Idx + Step; i++) {
+ uint8_t Counter = (Bundle >> (i * 8)) & 0xff;
+ if (!Counter) continue;
+ Counters[i] = 0;
+ unsigned Bit = 0;
+ /**/ if (Counter >= 128) Bit = 7;
+ else if (Counter >= 32) Bit = 6;
+ else if (Counter >= 16) Bit = 5;
+ else if (Counter >= 8) Bit = 4;
+ else if (Counter >= 4) Bit = 3;
+ else if (Counter >= 3) Bit = 2;
+ else if (Counter >= 2) Bit = 1;
+ size_t Feature = (i * 8 + Bit);
+ if (C->AddFeature(Feature, InputSize, Shrink))
+ Res++;
}
}
+ if (UseValueProfile)
+ ValueProfileMap.ForEach([&](size_t Idx) {
+ if (C->AddFeature(NumGuards + Idx, InputSize, Shrink))
+ Res++;
+ });
+ return Res;
}
void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
const uintptr_t kBits = 12;
const uintptr_t kMask = (1 << kBits) - 1;
- CounterMap.AddValue((Caller & kMask) | ((Callee & kMask) << kBits));
+ uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
+ HandleValueProfile(Idx);
}
-void TracePC::PrintCoverage() {
- Printf("COVERAGE:\n");
- for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) {
- if (PCs[i])
- PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]);
+static bool IsInterestingCoverageFile(std::string &File) {
+ if (File.find("compiler-rt/lib/") != std::string::npos)
+ return false; // sanitizer internal.
+ if (File.find("/usr/lib/") != std::string::npos)
+ return false;
+ if (File.find("/usr/include/") != std::string::npos)
+ return false;
+ if (File == "<null>")
+ return false;
+ return true;
+}
+
+void TracePC::PrintNewPCs() {
+ if (DoPrintNewPCs) {
+ if (!PrintedPCs)
+ PrintedPCs = new std::set<uintptr_t>;
+ for (size_t i = 1; i < GetNumPCs(); i++)
+ if (PCs[i] && PrintedPCs->insert(PCs[i]).second)
+ PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PCs[i]);
}
}
+void TracePC::PrintCoverage() {
+ if (!EF->__sanitizer_symbolize_pc) {
+ Printf("INFO: __sanitizer_symbolize_pc is not available,"
+ " not printing coverage\n");
+ return;
+ }
+ std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule;
+ std::map<std::string, uintptr_t> ModuleOffsets;
+ std::set<std::string> CoveredFiles, CoveredFunctions, CoveredLines;
+ Printf("COVERAGE:\n");
+ for (size_t i = 1; i < GetNumPCs(); i++) {
+ if (!PCs[i]) continue;
+ std::string FileStr = DescribePC("%s", PCs[i]);
+ if (!IsInterestingCoverageFile(FileStr)) continue;
+ std::string FixedPCStr = DescribePC("%p", PCs[i]);
+ std::string FunctionStr = DescribePC("%F", PCs[i]);
+ std::string LineStr = DescribePC("%l", PCs[i]);
+ // TODO(kcc): get the module using some other way since this
+ // does not work with ASAN_OPTIONS=strip_path_prefix=something.
+ std::string Module = DescribePC("%m", PCs[i]);
+ std::string OffsetStr = DescribePC("%o", PCs[i]);
+ uintptr_t FixedPC = std::stol(FixedPCStr, 0, 16);
+ uintptr_t PcOffset = std::stol(OffsetStr, 0, 16);
+ ModuleOffsets[Module] = FixedPC - PcOffset;
+ CoveredPCsPerModule[Module].push_back(PcOffset);
+ CoveredFunctions.insert(FunctionStr);
+ CoveredFiles.insert(FileStr);
+ if (!CoveredLines.insert(FileStr + ":" + LineStr).second)
+ continue;
+ Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(),
+ FileStr.c_str(), LineStr.c_str());
+ }
-void TracePC::UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize) {
- if (!CurrentElementSize) return;
- for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) {
- if (!CounterMap.Get(Idx)) continue;
- Feature &Fe = FeatureSet[Idx];
- Fe.Count++;
- if (!Fe.SmallestElementSize || Fe.SmallestElementSize > CurrentElementSize) {
- Fe.SmallestElementIdx = CurrentElementIdx;
- Fe.SmallestElementSize = CurrentElementSize;
+ for (auto &M : CoveredPCsPerModule) {
+ std::set<std::string> UncoveredFiles, UncoveredFunctions;
+ std::map<std::string, std::set<int> > UncoveredLines; // Func+File => lines
+ auto &ModuleName = M.first;
+ auto &CoveredOffsets = M.second;
+ uintptr_t ModuleOffset = ModuleOffsets[ModuleName];
+ std::sort(CoveredOffsets.begin(), CoveredOffsets.end());
+ Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str());
+ // sancov does not yet fully support DSOs.
+ // std::string Cmd = "sancov -print-coverage-pcs " + ModuleName;
+ std::string Cmd = "objdump -d " + ModuleName +
+ " | grep 'call.*__sanitizer_cov_trace_pc_guard' | awk -F: '{print $1}'";
+ std::string SanCovOutput;
+ if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) {
+ Printf("INFO: Command failed: %s\n", Cmd.c_str());
+ continue;
}
+ std::istringstream ISS(SanCovOutput);
+ std::string S;
+ while (std::getline(ISS, S, '\n')) {
+ uintptr_t PcOffset = std::stol(S, 0, 16);
+ if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(),
+ PcOffset)) {
+ uintptr_t PC = ModuleOffset + PcOffset;
+ auto FileStr = DescribePC("%s", PC);
+ if (!IsInterestingCoverageFile(FileStr)) continue;
+ if (CoveredFiles.count(FileStr) == 0) {
+ UncoveredFiles.insert(FileStr);
+ continue;
+ }
+ auto FunctionStr = DescribePC("%F", PC);
+ if (CoveredFunctions.count(FunctionStr) == 0) {
+ UncoveredFunctions.insert(FunctionStr);
+ continue;
+ }
+ std::string LineStr = DescribePC("%l", PC);
+ uintptr_t Line = std::stoi(LineStr);
+ std::string FileLineStr = FileStr + ":" + LineStr;
+ if (CoveredLines.count(FileLineStr) == 0)
+ UncoveredLines[FunctionStr + " " + FileStr].insert(Line);
+ }
+ }
+ for (auto &FileLine: UncoveredLines)
+ for (int Line : FileLine.second)
+ Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line);
+ for (auto &Func : UncoveredFunctions)
+ Printf("UNCOVERED_FUNC: %s\n", Func.c_str());
+ for (auto &File : UncoveredFiles)
+ Printf("UNCOVERED_FILE: %s\n", File.c_str());
}
}
-void TracePC::PrintFeatureSet() {
- Printf("[id: cnt idx sz] ");
- for (size_t i = 0; i < kFeatureSetSize; i++) {
- auto &Fe = FeatureSet[i];
- if (!Fe.Count) continue;
- Printf("[%zd: %zd %zd %zd] ", i, Fe.Count, Fe.SmallestElementIdx,
- Fe.SmallestElementSize);
- }
- Printf("\n");
+// Value profile.
+// We keep track of various values that affect control flow.
+// These values are inserted into a bit-set-based hash map.
+// Every new bit in the map is treated as a new coverage.
+//
+// For memcmp/strcmp/etc the interesting value is the length of the common
+// prefix of the parameters.
+// For cmp instructions the interesting value is a XOR of the parameters.
+// The interesting value is mixed up with the PC and is then added to the map.
+
+void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n) {
+ if (!n) return;
+ size_t Len = std::min(n, (size_t)32);
+ const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
+ const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
+ size_t I = 0;
+ for (; I < Len; I++)
+ if (A1[I] != A2[I])
+ break;
+ size_t PC = reinterpret_cast<size_t>(caller_pc);
+ size_t Idx = I;
+ // if (I < Len)
+ // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
+ TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
+}
+
+void TracePC::AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
+ size_t n) {
+ if (!n) return;
+ size_t Len = std::min(n, (size_t)32);
+ const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
+ const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
+ size_t I = 0;
+ for (; I < Len; I++)
+ if (A1[I] != A2[I] || A1[I] == 0)
+ break;
+ size_t PC = reinterpret_cast<size_t>(caller_pc);
+ size_t Idx = I;
+ // if (I < Len && A1[I])
+ // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
+ TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
+}
+
+template <class T>
+ATTRIBUTE_TARGET_POPCNT
+#ifdef __clang__ // g++ can't handle this __attribute__ here :(
+__attribute__((always_inline))
+#endif // __clang__
+void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) {
+ uintptr_t PCuint = reinterpret_cast<uintptr_t>(PC);
+ uint64_t ArgXor = Arg1 ^ Arg2;
+ uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65]
+ uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance;
+ if (sizeof(T) == 4)
+ TORC4.Insert(ArgXor, Arg1, Arg2);
+ else if (sizeof(T) == 8)
+ TORC8.Insert(ArgXor, Arg1, Arg2);
+ HandleValueProfile(Idx);
}
} // namespace fuzzer
extern "C" {
__attribute__((visibility("default")))
-void __sanitizer_cov_trace_pc_guard(uintptr_t *Guard) {
+void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
uintptr_t PC = (uintptr_t)__builtin_return_address(0);
fuzzer::TPC.HandleTrace(Guard, PC);
}
__attribute__((visibility("default")))
-void __sanitizer_cov_trace_pc_guard_init(uintptr_t *Start, uintptr_t *Stop) {
+void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
fuzzer::TPC.HandleInit(Start, Stop);
}
@@ -153,4 +288,45 @@ void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
uintptr_t PC = (uintptr_t)__builtin_return_address(0);
fuzzer::TPC.HandleCallerCallee(PC, Callee);
}
+
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
+}
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
+}
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
+}
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
}
+
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
+ uint64_t N = Cases[0];
+ uint64_t *Vals = Cases + 2;
+ char *PC = (char*)__builtin_return_address(0);
+ for (size_t i = 0; i < N; i++)
+ if (Val != Vals[i])
+ fuzzer::TPC.HandleCmp(PC + i, Val, Vals[i]);
+}
+
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_div4(uint32_t Val) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint32_t)0);
+}
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_div8(uint64_t Val) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint64_t)0);
+}
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_gep(uintptr_t Idx) {
+ fuzzer::TPC.HandleCmp(__builtin_return_address(0), Idx, (uintptr_t)0);
+}
+
+} // extern "C"
diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.h b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h
index 0f2b6a878c4..4cce36354d7 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerTracePC.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h
@@ -12,39 +12,56 @@
#ifndef LLVM_FUZZER_TRACE_PC
#define LLVM_FUZZER_TRACE_PC
+#include <set>
+
#include "FuzzerDefs.h"
#include "FuzzerValueBitMap.h"
namespace fuzzer {
+// TableOfRecentCompares (TORC) remembers the most recently performed
+// comparisons of type T.
+// We record the arguments of CMP instructions in this table unconditionally
+// because it seems cheaper this way than to compute some expensive
+// conditions inside __sanitizer_cov_trace_cmp*.
+// After the unit has been executed we may decide to use the contents of
+// this table to populate a Dictionary.
+template<class T, size_t kSizeT>
+struct TableOfRecentCompares {
+ static const size_t kSize = kSizeT;
+ struct Pair {
+ T A, B;
+ };
+ void Insert(size_t Idx, T Arg1, T Arg2) {
+ Idx = Idx % kSize;
+ Table[Idx].A = Arg1;
+ Table[Idx].B = Arg2;
+ }
+
+ Pair Get(size_t I) { return Table[I % kSize]; }
+
+ Pair Table[kSize];
+};
+
class TracePC {
public:
- void HandleTrace(uintptr_t *guard, uintptr_t PC);
- void HandleInit(uintptr_t *start, uintptr_t *stop);
+ static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems;
+
+ void HandleTrace(uint32_t *guard, uintptr_t PC);
+ void HandleInit(uint32_t *start, uint32_t *stop);
void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee);
void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); }
- size_t GetTotalPCCoverage() { return TotalPCCoverage; }
- void ResetTotalPCCoverage() { TotalPCCoverage = 0; }
+ template <class T> void HandleCmp(void *PC, T Arg1, T Arg2);
+ size_t GetTotalPCCoverage();
void SetUseCounters(bool UC) { UseCounters = UC; }
void SetUseValueProfile(bool VP) { UseValueProfile = VP; }
- bool UpdateCounterMap(ValueBitMap *MaxCounterMap) {
- return MaxCounterMap->MergeFrom(CounterMap);
- }
+ void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }
+ size_t FinalizeTrace(InputCorpus *C, size_t InputSize, bool Shrink);
bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap) {
return UseValueProfile && MaxValueProfileMap->MergeFrom(ValueProfileMap);
}
- void FinalizeTrace();
-
- size_t GetNewPCIDs(uintptr_t **NewPCIDsPtr) {
- *NewPCIDsPtr = NewPCIDs;
- return Min(kMaxNewPCIDs, NumNewPCIDs);
- }
-
- uintptr_t GetPCbyPCID(uintptr_t PCID) { return PCs[PCID]; }
void ResetMaps() {
- NumNewPCIDs = 0;
- CounterMap.Reset();
ValueProfileMap.Reset();
memset(Counters, 0, sizeof(Counters));
}
@@ -52,26 +69,35 @@ class TracePC {
void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
void PrintFeatureSet();
- void ResetGuards();
-
void PrintModuleInfo();
void PrintCoverage();
+ void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n);
+ void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
+ size_t n);
+
+ bool UsingTracePcGuard() const {return NumModules; }
+
+ static const size_t kTORCSize = 1 << 5;
+ TableOfRecentCompares<uint32_t, kTORCSize> TORC4;
+ TableOfRecentCompares<uint64_t, kTORCSize> TORC8;
+
+ void PrintNewPCs();
+ size_t GetNumPCs() const { return Min(kNumPCs, NumGuards + 1); }
+ uintptr_t GetPC(size_t Idx) {
+ assert(Idx < GetNumPCs());
+ return PCs[Idx];
+ }
+
private:
bool UseCounters = false;
bool UseValueProfile = false;
- size_t TotalPCCoverage = 0;
-
- static const size_t kMaxNewPCIDs = 1024;
- uintptr_t NewPCIDs[kMaxNewPCIDs];
- size_t NumNewPCIDs = 0;
- void AddNewPCID(uintptr_t PCID) {
- NewPCIDs[(NumNewPCIDs++) % kMaxNewPCIDs] = PCID;
- }
+ bool DoPrintNewPCs = false;
struct Module {
- uintptr_t *Start, *Stop;
+ uint32_t *Start, *Stop;
};
Module Modules[4096];
@@ -81,20 +107,12 @@ private:
static const size_t kNumCounters = 1 << 14;
alignas(8) uint8_t Counters[kNumCounters];
- static const size_t kNumPCs = 1 << 20;
+ static const size_t kNumPCs = 1 << 24;
uintptr_t PCs[kNumPCs];
- ValueBitMap CounterMap;
- ValueBitMap ValueProfileMap;
-
- struct Feature {
- size_t Count;
- size_t SmallestElementIdx;
- size_t SmallestElementSize;
- };
+ std::set<uintptr_t> *PrintedPCs;
- static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems;
- Feature FeatureSet[kFeatureSetSize];
+ ValueBitMap ValueProfileMap;
};
extern TracePC TPC;
diff --git a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp
index 97d5935008b..9cccfcbc26f 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp
@@ -6,71 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-// This file implements a mutation algorithm based on instruction traces and
-// on taint analysis feedback from DFSan.
-//
-// Instruction traces are special hooks inserted by the compiler around
-// interesting instructions. Currently supported traces:
-// * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction,
-// receives the type, size and arguments of ICMP.
-//
-// Every time a traced event is intercepted we analyse the data involved
-// in the event and suggest a mutation for future executions.
-// For example if 4 bytes of data that derive from input bytes {4,5,6,7}
-// are compared with a constant 12345,
-// we try to insert 12345, 12344, 12346 into bytes
-// {4,5,6,7} of the next fuzzed inputs.
-//
-// The fuzzer can work only with the traces, or with both traces and DFSan.
-//
-// DataFlowSanitizer (DFSan) is a tool for
-// generalised dynamic data flow (taint) analysis:
-// http://clang.llvm.org/docs/DataFlowSanitizer.html .
-//
-// The approach with DFSan-based fuzzing has some similarity to
-// "Taint-based Directed Whitebox Fuzzing"
-// by Vijay Ganesh & Tim Leek & Martin Rinard:
-// http://dspace.mit.edu/openaccess-disseminate/1721.1/59320,
-// but it uses a full blown LLVM IR taint analysis and separate instrumentation
-// to analyze all of the "attack points" at once.
-//
-// Workflow with DFSan:
-// * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation.
-// * The code under test is compiled with DFSan *and* with instruction traces.
-// * Every call to HOOK(a,b) is replaced by DFSan with
-// __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK
-// gets all the taint labels for the arguments.
-// * At the Fuzzer startup we assign a unique DFSan label
-// to every byte of the input string (Fuzzer::CurrentUnitData) so that
-// for any chunk of data we know which input bytes it has derived from.
-// * The __dfsw_* functions (implemented in this file) record the
-// parameters (i.e. the application data and the corresponding taint labels)
-// in a global state.
-//
-// Parts of this code will not function when DFSan is not linked in.
-// Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer
-// we redeclare the dfsan_* interface functions as weak and check if they
-// are nullptr before calling.
-// If this approach proves to be useful we may add attribute(weak) to the
-// dfsan declarations in dfsan_interface.h
-//
-// This module is in the "proof of concept" stage.
-// It is capable of solving only the simplest puzzles
-// like test/dfsan/DFSanSimpleCmpTest.cpp.
+// Data tracing.
//===----------------------------------------------------------------------===//
-/* Example of manual usage (-fsanitize=dataflow is optional):
-(
- cd $LLVM/lib/Fuzzer/
- clang -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp
- clang++ -O0 -std=c++11 -fsanitize-coverage=edge,trace-cmp \
- -fsanitize=dataflow \
- test/SimpleCmpTest.cpp Fuzzer*.o
- ./a.out -use_traces=1
-)
-*/
-
-#include "FuzzerDFSan.h"
#include "FuzzerInternal.h"
#include "FuzzerDictionary.h"
#include "FuzzerMutate.h"
@@ -83,90 +21,8 @@
#include <map>
#include <set>
-#if !LLVM_FUZZER_SUPPORTS_DFSAN
-// Stubs for dfsan for platforms where dfsan does not exist and weak
-// functions don't work.
-extern "C" {
-dfsan_label dfsan_create_label(const char *desc, void *userdata) { return 0; }
-void dfsan_set_label(dfsan_label label, void *addr, size_t size) {}
-void dfsan_add_label(dfsan_label label, void *addr, size_t size) {}
-const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
- return nullptr;
-}
-dfsan_label dfsan_read_label(const void *addr, size_t size) { return 0; }
-} // extern "C"
-#endif // !LLVM_FUZZER_SUPPORTS_DFSAN
-
namespace fuzzer {
-// These values are copied from include/llvm/IR/InstrTypes.h.
-// We do not include the LLVM headers here to remain independent.
-// If these values ever change, an assertion in ComputeCmp will fail.
-enum Predicate {
- ICMP_EQ = 32, ///< equal
- ICMP_NE = 33, ///< not equal
- ICMP_UGT = 34, ///< unsigned greater than
- ICMP_UGE = 35, ///< unsigned greater or equal
- ICMP_ULT = 36, ///< unsigned less than
- ICMP_ULE = 37, ///< unsigned less or equal
- ICMP_SGT = 38, ///< signed greater than
- ICMP_SGE = 39, ///< signed greater or equal
- ICMP_SLT = 40, ///< signed less than
- ICMP_SLE = 41, ///< signed less or equal
-};
-
-template <class U, class S>
-bool ComputeCmp(size_t CmpType, U Arg1, U Arg2) {
- switch(CmpType) {
- case ICMP_EQ : return Arg1 == Arg2;
- case ICMP_NE : return Arg1 != Arg2;
- case ICMP_UGT: return Arg1 > Arg2;
- case ICMP_UGE: return Arg1 >= Arg2;
- case ICMP_ULT: return Arg1 < Arg2;
- case ICMP_ULE: return Arg1 <= Arg2;
- case ICMP_SGT: return (S)Arg1 > (S)Arg2;
- case ICMP_SGE: return (S)Arg1 >= (S)Arg2;
- case ICMP_SLT: return (S)Arg1 < (S)Arg2;
- case ICMP_SLE: return (S)Arg1 <= (S)Arg2;
- default: assert(0 && "unsupported CmpType");
- }
- return false;
-}
-
-static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1,
- uint64_t Arg2) {
- if (CmpSize == 8) return ComputeCmp<uint64_t, int64_t>(CmpType, Arg1, Arg2);
- if (CmpSize == 4) return ComputeCmp<uint32_t, int32_t>(CmpType, Arg1, Arg2);
- if (CmpSize == 2) return ComputeCmp<uint16_t, int16_t>(CmpType, Arg1, Arg2);
- if (CmpSize == 1) return ComputeCmp<uint8_t, int8_t>(CmpType, Arg1, Arg2);
- // Other size, ==
- if (CmpType == ICMP_EQ) return Arg1 == Arg2;
- // assert(0 && "unsupported cmp and type size combination");
- return true;
-}
-
-// As a simplification we use the range of input bytes instead of a set of input
-// bytes.
-struct LabelRange {
- uint16_t Beg, End; // Range is [Beg, End), thus Beg==End is an empty range.
-
- LabelRange(uint16_t Beg = 0, uint16_t End = 0) : Beg(Beg), End(End) {}
-
- static LabelRange Join(LabelRange LR1, LabelRange LR2) {
- if (LR1.Beg == LR1.End) return LR2;
- if (LR2.Beg == LR2.End) return LR1;
- return {std::min(LR1.Beg, LR2.Beg), std::max(LR1.End, LR2.End)};
- }
- LabelRange &Join(LabelRange LR) {
- return *this = Join(*this, LR);
- }
- static LabelRange Singleton(const dfsan_label_info *LI) {
- uint16_t Idx = (uint16_t)(uintptr_t)LI->userdata;
- assert(Idx > 0);
- return {(uint16_t)(Idx - 1), Idx};
- }
-};
-
// For now, very simple: put Size bytes of Data at position Pos.
struct TraceBasedMutation {
uint32_t Pos;
@@ -178,10 +34,8 @@ static bool RecordingMemcmp = false;
static bool RecordingMemmem = false;
static bool DoingMyOwnMemmem = false;
-struct ScopedDoingMyOwnMemmem {
- ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
- ~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
-};
+ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
+ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
class TraceState {
public:
@@ -189,17 +43,6 @@ public:
const Fuzzer *F)
: MD(MD), Options(Options), F(F) {}
- LabelRange GetLabelRange(dfsan_label L);
- void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
- uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
- dfsan_label L2);
- void DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
- const uint8_t *Data2, dfsan_label L1,
- dfsan_label L2);
- void DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val,
- size_t NumCases, uint64_t *Cases, dfsan_label L);
- void TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
- uint64_t Arg1, uint64_t Arg2);
void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
const uint8_t *Data2);
@@ -270,17 +113,6 @@ public:
InterestingWords.insert(W);
}
- void EnsureDfsanLabels(size_t Size) {
- for (; LastDfsanLabel < Size; LastDfsanLabel++) {
- dfsan_label L = dfsan_create_label("input", (void *)(LastDfsanLabel + 1));
- // We assume that no one else has called dfsan_create_label before.
- if (L != LastDfsanLabel + 1) {
- Printf("DFSan labels are not starting from 1, exiting\n");
- exit(1);
- }
- }
- }
-
private:
bool IsTwoByteData(uint64_t Data) {
int64_t Signed = static_cast<int64_t>(Data);
@@ -308,8 +140,6 @@ public:
TraceBasedMutation Mutations[kMaxMutations];
// TODO: std::set is too inefficient, need to have a custom DS here.
std::set<Word> InterestingWords;
- LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)];
- size_t LastDfsanLabel = 0;
MutationDispatcher &MD;
const FuzzingOptions Options;
const Fuzzer *F;
@@ -317,93 +147,6 @@ public:
size_t AutoDictAdds = 0;
};
-
-LabelRange TraceState::GetLabelRange(dfsan_label L) {
- LabelRange &LR = LabelRanges[L];
- if (LR.Beg < LR.End || L == 0)
- return LR;
- const dfsan_label_info *LI = dfsan_get_label_info(L);
- if (LI->l1 || LI->l2)
- return LR = LabelRange::Join(GetLabelRange(LI->l1), GetLabelRange(LI->l2));
- return LR = LabelRange::Singleton(LI);
-}
-
-void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
- uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
- dfsan_label L2) {
- assert(ReallyHaveDFSan());
- if (!F->InFuzzingThread()) return;
- if (L1 == 0 && L2 == 0)
- return; // Not actionable.
- if (L1 != 0 && L2 != 0)
- return; // Probably still actionable.
- bool Res = ComputeCmp(CmpSize, CmpType, Arg1, Arg2);
- uint64_t Data = L1 ? Arg2 : Arg1;
- LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
-
- for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
- AddMutation(Pos, CmpSize, Data);
- AddMutation(Pos, CmpSize, Data + 1);
- AddMutation(Pos, CmpSize, Data - 1);
- }
-
- if (CmpSize > (size_t)(LR.End - LR.Beg))
- AddMutation(LR.Beg, (unsigned)(LR.End - LR.Beg), Data);
-
-
- if (Options.Verbosity >= 3)
- Printf("DFSanCmpCallback: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 "
- "%d MU %zd\n",
- PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, NumMutations);
-}
-
-void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
- const uint8_t *Data2, dfsan_label L1,
- dfsan_label L2) {
-
- assert(ReallyHaveDFSan());
- if (!RecordingMemcmp || !F->InFuzzingThread()) return;
- if (L1 == 0 && L2 == 0)
- return; // Not actionable.
- if (L1 != 0 && L2 != 0)
- return; // Probably still actionable.
-
- const uint8_t *Data = L1 ? Data2 : Data1;
- LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
- for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
- AddMutation(Pos, CmpSize, Data);
- if (Options.Verbosity >= 3)
- Printf("DFSanMemcmpCallback: Pos %d Size %d\n", Pos, CmpSize);
- }
-}
-
-void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
- uint64_t Val, size_t NumCases,
- uint64_t *Cases, dfsan_label L) {
- assert(ReallyHaveDFSan());
- if (!F->InFuzzingThread()) return;
- if (!L) return; // Not actionable.
- LabelRange LR = GetLabelRange(L);
- size_t ValSize = ValSizeInBits / 8;
- bool TryShort = IsTwoByteData(Val);
- for (size_t i = 0; i < NumCases; i++)
- TryShort &= IsTwoByteData(Cases[i]);
-
- for (size_t Pos = LR.Beg; Pos + ValSize <= LR.End; Pos++)
- for (size_t i = 0; i < NumCases; i++)
- AddMutation(Pos, ValSize, Cases[i]);
-
- if (TryShort)
- for (size_t Pos = LR.Beg; Pos + 2 <= LR.End; Pos++)
- for (size_t i = 0; i < NumCases; i++)
- AddMutation(Pos, 2, Cases[i]);
-
- if (Options.Verbosity >= 3)
- Printf("DFSanSwitchCallback: PC %lx Val %zd SZ %zd # %zd L %d: {%d, %d} "
- "TryShort %d\n",
- PC, Val, ValSize, NumCases, L, LR.Beg, LR.End, TryShort);
-}
-
int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
size_t DataSize) {
if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
@@ -449,22 +192,6 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
return Res;
}
-void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
- uint64_t Arg1, uint64_t Arg2) {
- if (!F->InFuzzingThread()) return;
- if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2)
- return; // No reason to mutate.
- int Added = 0;
- Added += TryToAddDesiredData(Arg1, Arg2, CmpSize);
- Added += TryToAddDesiredData(Arg2, Arg1, CmpSize);
- if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) {
- Added += TryToAddDesiredData(Arg1, Arg2, 2);
- Added += TryToAddDesiredData(Arg2, Arg1, 2);
- }
- if (Options.Verbosity >= 3 && Added)
- Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2);
-}
-
void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
const uint8_t *Data2) {
if (!RecordingMemcmp || !F->InFuzzingThread()) return;
@@ -511,14 +238,6 @@ void Fuzzer::StopTraceRecording() {
TS->StopTraceRecording();
}
-void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) {
- if (!Options.UseMemcmp) return;
- if (!ReallyHaveDFSan()) return;
- TS->EnsureDfsanLabels(Size);
- for (size_t i = 0; i < Size; i++)
- dfsan_set_label(i + 1, &Data[i], 1);
-}
-
void Fuzzer::InitializeTraceState() {
if (!Options.UseMemcmp) return;
TS = new TraceState(MD, Options, this);
@@ -530,128 +249,12 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) {
return Len;
}
-// Value profile.
-// We keep track of various values that affect control flow.
-// These values are inserted into a bit-set-based hash map.
-// Every new bit in the map is treated as a new coverage.
-//
-// For memcmp/strcmp/etc the interesting value is the length of the common
-// prefix of the parameters.
-// For cmp instructions the interesting value is a XOR of the parameters.
-// The interesting value is mixed up with the PC and is then added to the map.
-
-static void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
- size_t n) {
- if (!n) return;
- size_t Len = std::min(n, (size_t)32);
- const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
- const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
- size_t I = 0;
- for (; I < Len; I++)
- if (A1[I] != A2[I])
- break;
- size_t PC = reinterpret_cast<size_t>(caller_pc);
- size_t Idx = I;
- // if (I < Len)
- // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
- TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
-}
-
-static void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
- size_t n) {
- if (!n) return;
- size_t Len = std::min(n, (size_t)32);
- const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
- const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
- size_t I = 0;
- for (; I < Len; I++)
- if (A1[I] != A2[I] || A1[I] == 0)
- break;
- size_t PC = reinterpret_cast<size_t>(caller_pc);
- size_t Idx = I;
- // if (I < Len && A1[I])
- // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
- TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
-}
-
-ATTRIBUTE_TARGET_POPCNT
-static void AddValueForCmp(void *PCptr, uint64_t Arg1, uint64_t Arg2) {
- if (Arg1 == Arg2)
- return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
- uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) - 1; // [0,63]
- uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
- TPC.HandleValueProfile(Idx);
-}
-
-static void AddValueForSingleVal(void *PCptr, uintptr_t Val) {
- if (!Val) return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
- uint64_t ArgDistance = __builtin_popcountl(Val) - 1; // [0,63]
- uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
- TPC.HandleValueProfile(Idx);
-}
-
} // namespace fuzzer
using fuzzer::TS;
using fuzzer::RecordingMemcmp;
extern "C" {
-void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
- uint64_t Arg2, dfsan_label L0,
- dfsan_label L1, dfsan_label L2) {
-}
-
-#define DFSAN_CMP_CALLBACK(N) \
- void __dfsw___sanitizer_cov_trace_cmp##N(uint64_t Arg1, uint64_t Arg2, \
- dfsan_label L1, dfsan_label L2) { \
- }
-
-DFSAN_CMP_CALLBACK(1)
-DFSAN_CMP_CALLBACK(2)
-DFSAN_CMP_CALLBACK(4)
-DFSAN_CMP_CALLBACK(8)
-#undef DFSAN_CMP_CALLBACK
-
-void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
- dfsan_label L1, dfsan_label L2) {
-}
-
-void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
- size_t n, dfsan_label s1_label,
- dfsan_label s2_label, dfsan_label n_label) {
- if (!RecordingMemcmp) return;
- dfsan_label L1 = dfsan_read_label(s1, n);
- dfsan_label L2 = dfsan_read_label(s2, n);
- TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
- reinterpret_cast<const uint8_t *>(s2), L1, L2);
-}
-
-void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
- size_t n, dfsan_label s1_label,
- dfsan_label s2_label, dfsan_label n_label) {
- if (!RecordingMemcmp) return;
- n = std::min(n, fuzzer::InternalStrnlen(s1, n));
- n = std::min(n, fuzzer::InternalStrnlen(s2, n));
- dfsan_label L1 = dfsan_read_label(s1, n);
- dfsan_label L2 = dfsan_read_label(s2, n);
- TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
- reinterpret_cast<const uint8_t *>(s2), L1, L2);
-}
-
-void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2,
- dfsan_label s1_label, dfsan_label s2_label) {
- if (!RecordingMemcmp) return;
- size_t Len1 = strlen(s1);
- size_t Len2 = strlen(s2);
- size_t N = std::min(Len1, Len2);
- if (N <= 1) return; // Not interesting.
- dfsan_label L1 = dfsan_read_label(s1, Len1);
- dfsan_label L2 = dfsan_read_label(s2, Len2);
- TS->DFSanMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
- reinterpret_cast<const uint8_t *>(s2), L1, L2);
-}
// We may need to avoid defining weak hooks to stay compatible with older clang.
#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
@@ -661,7 +264,7 @@ void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2,
#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
const void *s2, size_t n, int result) {
- fuzzer::AddValueForMemcmp(caller_pc, s1, s2, n);
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n);
if (!RecordingMemcmp) return;
if (result == 0) return; // No reason to mutate.
if (n <= 1) return; // Not interesting.
@@ -671,7 +274,7 @@ void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
const char *s2, size_t n, int result) {
- fuzzer::AddValueForStrcmp(caller_pc, s1, s2, n);
+ fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, n);
if (!RecordingMemcmp) return;
if (result == 0) return; // No reason to mutate.
size_t Len1 = fuzzer::InternalStrnlen(s1, n);
@@ -685,7 +288,7 @@ void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
const char *s2, int result) {
- fuzzer::AddValueForStrcmp(caller_pc, s1, s2, 64);
+ fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, 64);
if (!RecordingMemcmp) return;
if (result == 0) return; // No reason to mutate.
size_t Len1 = strlen(s1);
@@ -719,47 +322,4 @@ void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
}
#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
-
-// TODO: this one will not be used with the newest clang. Remove it.
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
- uint64_t Arg2) {
- fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
-}
-
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_cmp8(uint64_t Arg1, int64_t Arg2) {
- fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
-}
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_cmp4(uint32_t Arg1, int32_t Arg2) {
- fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
-}
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_cmp2(uint16_t Arg1, int16_t Arg2) {
- fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
-}
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_cmp1(uint8_t Arg1, int8_t Arg2) {
- fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
-}
-
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
- // TODO(kcc): support value profile here.
-}
-
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_div4(uint32_t Val) {
- fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
-}
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_div8(uint64_t Val) {
- fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
-}
-__attribute__((visibility("default")))
-void __sanitizer_cov_trace_gep(uintptr_t Idx) {
- fuzzer::AddValueForSingleVal(__builtin_return_address(0), Idx);
-}
-
} // extern "C"
diff --git a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp
index 254d9c826df..d845333a169 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp
@@ -19,6 +19,7 @@
#include <cassert>
#include <chrono>
#include <cstring>
+#include <stdio.h>
#include <signal.h>
#include <sstream>
#include <unistd.h>
@@ -306,4 +307,14 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
Printf(FallbackFMT, PC);
}
+bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) {
+ FILE *Pipe = popen(Command.c_str(), "r");
+ if (!Pipe) return false;
+ char Buff[1024];
+ size_t N;
+ while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0)
+ Out->append(Buff, N);
+ return true;
+}
+
} // namespace fuzzer
diff --git a/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h b/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h
index 97f4c5e51b9..0692acd13ee 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h
@@ -68,6 +68,15 @@ struct ValueBitMap {
return OldNumBits < NumBits;
}
+ template <class Callback>
+ void ForEach(Callback CB) {
+ for (size_t i = 0; i < kMapSizeInWords; i++)
+ if (uintptr_t M = Map[i])
+ for (size_t j = 0; j < sizeof(M) * 8; j++)
+ if (M & ((uintptr_t)1 << j))
+ CB(i * sizeof(M) * 8 + j);
+ }
+
private:
size_t NumBits = 0;
uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512)));
diff --git a/chromium/third_party/libFuzzer/src/build.sh b/chromium/third_party/libFuzzer/src/build.sh
index 92d7b8cdbf7..27c148ad43d 100755
--- a/chromium/third_party/libFuzzer/src/build.sh
+++ b/chromium/third_party/libFuzzer/src/build.sh
@@ -1,7 +1,7 @@
#!/bin/bash
LIBFUZZER_SRC_DIR=$(dirname $0)
for f in $LIBFUZZER_SRC_DIR/*.cpp; do
- clang -O2 -std=c++11 $f -c &
+ clang -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c &
done
wait
rm -f libFuzzer.a
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh
deleted file mode 100755
index 69fa7241b86..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-
-[ -e $(basename $0) ] && echo "PLEASE USE THIS SCRIPT FROM ANOTHER DIR" && exit 1
-SCRIPT_DIR=$(dirname $0)
-EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR)
-LIBFUZZER_SRC=$(dirname $(dirname $SCRIPT_DIR))
-JOBS=20
-
-# FUZZ_CXXFLAGS=" -g -fsanitize=address -fsanitize-coverage=edge"
-FUZZ_CXXFLAGS=" -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,trace-gep"
-
-get() {
- [ ! -e SRC ] && git clone https://github.com/openssl/openssl.git SRC && (cd SRC && git checkout OpenSSL_1_0_1f)
-# [ ! -e SRC ] && wget https://www.openssl.org/source/openssl-1.0.1f.tar.gz && tar xf openssl-1.0.1f.tar.gz && mv openssl-1.0.1f SRC
-}
-build_lib() {
- rm -rf BUILD
- cp -rf SRC BUILD
- (cd BUILD && ./config && make clean && make CC="clang $FUZZ_CXXFLAGS" -j $JOBS)
-}
-
-get
-build_lib
-$LIBFUZZER_SRC/build.sh
-clang++ -g $SCRIPT_DIR/target.cc -DCERT_PATH=\"$SCRIPT_DIR/\" $FUZZ_CXXFLAGS BUILD/libssl.a BUILD/libcrypto.a libFuzzer.a -o $EXECUTABLE_NAME_BASE
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key
deleted file mode 100644
index 4e887edb0e1..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key
+++ /dev/null
@@ -1,10 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA1AdZNDVOA9cXm97f
-erp1bukz2kohjToJS6Ma8fOb36VV9lQGmDNsJanXFiqafOgV+kh1HXqZ3l1I0JmZ
-71b+QQIDAQABAkAHGfPn5r0lLcgRpWZQwvv56f+dmQwEoeP7z4uwfNtEo0JcRD66
-1WRCvx3LE0VbNeaEdNmSPiRXhlwIggjfrBi9AiEA9UusPBcEp/QcPGs96nQQdQzE
-fw4x0HL/eSV3qHimT6MCIQDdSAiX4Ouxoiwn/9KhDMcZXRYX/OPzj6w8u1YIH7BI
-ywIgSozbJdAhHCJ2ym4VfUIVFl3xAmSAA0hQGLOocE1qzl0CIQDRicOxZmhqBiKA
-IgznOn1StEYWov+MhRFZVSBLgw5gbwIgJzOlSlu0Y22hEUsLCKyHBrCAZZHcZ020
-20pfogmQYn0=
------END PRIVATE KEY-----
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem
deleted file mode 100644
index a7962debc37..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem
+++ /dev/null
@@ -1,10 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBYTCCAQugAwIBAgIJAMPQQtUHkx+KMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV
-BAMMAWEwHhcNMTYwOTI0MjIyMDUyWhcNNDQwMjA5MjIyMDUyWjAMMQowCAYDVQQD
-DAFhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANQHWTQ1TgPXF5ve33q6dW7pM9pK
-IY06CUujGvHzm9+lVfZUBpgzbCWp1xYqmnzoFfpIdR16md5dSNCZme9W/kECAwEA
-AaNQME4wHQYDVR0OBBYEFCXtEo9rkLuKGSlm0mFE4Yk/HDJVMB8GA1UdIwQYMBaA
-FCXtEo9rkLuKGSlm0mFE4Yk/HDJVMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL
-BQADQQCnldOnbdNJZxBO/J+979Urg8qDp8MnlN0979AmK1P5/YzPnAF4BU7QTOTE
-imS5qZ0MvziBa81nVlnnFRkIezcD
------END CERTIFICATE-----
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc
deleted file mode 100644
index 9dc2d5dc21b..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <assert.h>
-#include <stdint.h>
-#include <stddef.h>
-
-#ifndef CERT_PATH
-# define CERT_PATH
-#endif
-
-SSL_CTX *Init() {
- SSL_library_init();
- SSL_load_error_strings();
- ERR_load_BIO_strings();
- OpenSSL_add_all_algorithms();
- SSL_CTX *sctx;
- assert (sctx = SSL_CTX_new(TLSv1_method()));
- /* These two file were created with this command:
- openssl req -x509 -newkey rsa:512 -keyout server.key \
- -out server.pem -days 9999 -nodes -subj /CN=a/
- */
- assert(SSL_CTX_use_certificate_file(sctx, CERT_PATH "server.pem",
- SSL_FILETYPE_PEM));
- assert(SSL_CTX_use_PrivateKey_file(sctx, CERT_PATH "server.key",
- SSL_FILETYPE_PEM));
- return sctx;
-}
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- static SSL_CTX *sctx = Init();
- SSL *server = SSL_new(sctx);
- BIO *sinbio = BIO_new(BIO_s_mem());
- BIO *soutbio = BIO_new(BIO_s_mem());
- SSL_set_bio(server, sinbio, soutbio);
- SSL_set_accept_state(server);
- BIO_write(sinbio, Data, Size);
- SSL_do_handshake(server);
- SSL_free(server);
- return 0;
-}
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh
deleted file mode 100755
index 34132e5b300..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-# Find heartbleed.
-set -x
-[ -e openssl-1.0.1f ] && ./openssl-1.0.1f -max_total_time=300 2>&1 | tee log
-grep -Pzo "(?s)ERROR: AddressSanitizer: heap-buffer-overflow.*READ of size.*#1 0x.* in tls1_process_heartbeat .*ssl/t1_lib.c:2586" log
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh
deleted file mode 100755
index c2533bb0dc3..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-[ -e $(basename $0) ] && echo "PLEASE USE THIS SCRIPT FROM ANOTHER DIR" && exit 1
-SCRIPT_DIR=$(dirname $0)
-EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR)
-LIBFUZZER_SRC=$(dirname $(dirname $SCRIPT_DIR))
-
-FUZZ_CXXFLAGS="-O2 -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div"
-
-get() {
- [ ! -e SRC ] && git clone https://github.com/google/re2.git SRC && (cd SRC && git reset --hard 499ef7eff7455ce9c9fae86111d4a77b6ac335de)
-}
-build_lib() {
- rm -rf BUILD
- cp -rf SRC BUILD
- (cd BUILD && make clean && CXX=clang++ CXXFLAGS="$FUZZ_CXXFLAGS" make -j)
-}
-
-get
-build_lib
-$LIBFUZZER_SRC/build.sh
-clang++ -g $SCRIPT_DIR/target.cc -I BUILD BUILD/obj/libre2.a libFuzzer.a $FUZZ_CXXFLAGS -o $EXECUTABLE_NAME_BASE
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc
deleted file mode 100644
index 834db4e0ff2..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <string>
-#include "re2/re2.h"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- if (size < 3) return 0;
- uint16_t f = (data[0] << 16) + data[1];
- RE2::Options opt;
- opt.set_log_errors(false);
- if (f & 1) opt.set_encoding(RE2::Options::EncodingLatin1);
- opt.set_posix_syntax(f & 2);
- opt.set_longest_match(f & 4);
- opt.set_literal(f & 8);
- opt.set_never_nl(f & 16);
- opt.set_dot_nl(f & 32);
- opt.set_never_capture(f & 64);
- opt.set_case_sensitive(f & 128);
- opt.set_perl_classes(f & 256);
- opt.set_word_boundary(f & 512);
- opt.set_one_line(f & 1024);
- const char *b = reinterpret_cast<const char*>(data) + 2;
- const char *e = reinterpret_cast<const char*>(data) + size;
- std::string s1(b, e);
- RE2 re(s1, opt);
- if (re.ok())
- RE2::FullMatch(s1, re);
- return 0;
-}
diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh
deleted file mode 100755
index 3e07a956234..00000000000
--- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-set -x
-SCRIPT_DIR=$(dirname $0)
-EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR)
-CORPUS=CORPUS-$EXECUTABLE_NAME_BASE
-JOBS=8
-rm -rf $CORPUS
-mkdir $CORPUS
-[ -e $EXECUTABLE_NAME_BASE ] && ./$EXECUTABLE_NAME_BASE -exit_on_src_pos=re2/dfa.cc:474 -exit_on_src_pos=re2/dfa.cc:474 -runs=1000000 -jobs=$JOBS -workers=$JOBS $CORPUS
-grep "INFO: found line matching 're2/dfa.cc:474', exiting." fuzz-0.log
diff --git a/chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c b/chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c
new file mode 100644
index 00000000000..0d76ea49e79
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c
@@ -0,0 +1,41 @@
+/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This main() function can be linked to a fuzz target (i.e. a library
+// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize())
+// instead of libFuzzer. This main() function will not perform any fuzzing
+// but will simply feed all input files one by one to the fuzz target.
+//
+// Use this file to provide reproducers for bugs when linking against libFuzzer
+// or other fuzzing engine is undesirable.
+//===----------------------------------------------------------------------===*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
+__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
+int main(int argc, char **argv) {
+ fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1);
+ if (LLVMFuzzerInitialize)
+ LLVMFuzzerInitialize(&argc, &argv);
+ for (int i = 1; i < argc; i++) {
+ fprintf(stderr, "Running: %s\n", argv[i]);
+ FILE *f = fopen(argv[i], "r");
+ assert(f);
+ fseek(f, 0, SEEK_END);
+ size_t len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ unsigned char *buf = (unsigned char*)malloc(len);
+ size_t n_read = fread(buf, 1, len, f);
+ assert(n_read == len);
+ LLVMFuzzerTestOneInput(buf, len);
+ free(buf);
+ fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read);
+ }
+}