aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuzzer
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:22 +0000
commit3a1720af1d7f43edc5b214cde0be11bfb94d077e (patch)
tree029e0ff2d5e3c0eaf2405fd8e669555fdf5e1297 /lib/fuzzer
parent8f3cadc28cb2bb9e8f9d69eeaaea1f57f2f7b2ab (diff)
downloadsrc-vendor/compiler-rt.tar.gz
src-vendor/compiler-rt.zip
Vendor import of stripped compiler-rt trunk r375505, the last commitvendor/compiler-rt/compiler-rt-trunk-r375505vendor/compiler-rt
before the upstream Subversion repository was made read-only, and the LLVM project migrated to GitHub: https://llvm.org/svn/llvm-project/compiler-rt/trunk@375505
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=353944 svn path=/vendor/compiler-rt/compiler-rt-r375505/; revision=353945; tag=vendor/compiler-rt/compiler-rt-trunk-r375505
Diffstat (limited to 'lib/fuzzer')
-rw-r--r--lib/fuzzer/FuzzerBuiltinsMsvc.h22
-rw-r--r--lib/fuzzer/FuzzerDefs.h5
-rw-r--r--lib/fuzzer/FuzzerDriver.cpp1
-rw-r--r--lib/fuzzer/FuzzerExtFunctions.def11
-rw-r--r--lib/fuzzer/FuzzerFlags.def3
-rw-r--r--lib/fuzzer/FuzzerInternal.h3
-rw-r--r--lib/fuzzer/FuzzerLoop.cpp19
-rw-r--r--lib/fuzzer/FuzzerMerge.cpp82
-rw-r--r--lib/fuzzer/FuzzerOptions.h1
-rw-r--r--lib/fuzzer/FuzzerTracePC.cpp41
-rw-r--r--lib/fuzzer/FuzzerTracePC.h3
-rw-r--r--lib/fuzzer/FuzzerUtil.h2
-rw-r--r--lib/fuzzer/FuzzerUtilFuchsia.cpp26
-rw-r--r--lib/fuzzer/FuzzerUtilPosix.cpp6
-rw-r--r--lib/fuzzer/FuzzerUtilWindows.cpp4
-rw-r--r--lib/fuzzer/utils/FuzzedDataProvider.h245
16 files changed, 117 insertions, 357 deletions
diff --git a/lib/fuzzer/FuzzerBuiltinsMsvc.h b/lib/fuzzer/FuzzerBuiltinsMsvc.h
index 82709cfe7b40..bc65c60098be 100644
--- a/lib/fuzzer/FuzzerBuiltinsMsvc.h
+++ b/lib/fuzzer/FuzzerBuiltinsMsvc.h
@@ -15,9 +15,6 @@
#include "FuzzerDefs.h"
#if LIBFUZZER_MSVC
-#if !defined(_M_ARM) && !defined(_M_X64)
-#error "_BitScanReverse64 unavailable on this platform so MSVC is unsupported."
-#endif
#include <intrin.h>
#include <cstdint>
#include <cstdlib>
@@ -40,7 +37,18 @@ inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); }
// outside of Windows.
inline uint32_t Clzll(uint64_t X) {
unsigned long LeadZeroIdx = 0;
+
+#if !defined(_M_ARM) && !defined(_M_X64)
+ // Scan the high 32 bits.
+ if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X >> 32)))
+ return static_cast<int>(63 - (LeadZeroIdx + 32)); // Create a bit offset from the MSB.
+ // Scan the low 32 bits.
+ if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X)))
+ return static_cast<int>(63 - LeadZeroIdx);
+
+#else
if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx;
+#endif
return 64;
}
@@ -50,7 +58,13 @@ inline uint32_t Clz(uint32_t X) {
return 32;
}
-inline int Popcountll(unsigned long long X) { return __popcnt64(X); }
+inline int Popcountll(unsigned long long X) {
+#if !defined(_M_ARM) && !defined(_M_X64)
+ return __popcnt(X) + __popcnt(X >> 32);
+#else
+ return __popcnt64(X);
+#endif
+}
} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h
index 320b37d5f8e3..5dc2d8e1ac09 100644
--- a/lib/fuzzer/FuzzerDefs.h
+++ b/lib/fuzzer/FuzzerDefs.h
@@ -15,10 +15,11 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <memory>
+#include <set>
#include <string>
#include <vector>
-#include <set>
-#include <memory>
+
// Platform detection.
#ifdef __linux__
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp
index 54c7ff079585..44c90655b932 100644
--- a/lib/fuzzer/FuzzerDriver.cpp
+++ b/lib/fuzzer/FuzzerDriver.cpp
@@ -708,7 +708,6 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.FeaturesDir = Flags.features_dir;
if (Flags.collect_data_flow)
Options.CollectDataFlow = Flags.collect_data_flow;
- Options.LazyCounters = Flags.lazy_counters;
if (Flags.stop_file)
Options.StopFile = Flags.stop_file;
diff --git a/lib/fuzzer/FuzzerExtFunctions.def b/lib/fuzzer/FuzzerExtFunctions.def
index 41fa0fd2b748..51edf8444e94 100644
--- a/lib/fuzzer/FuzzerExtFunctions.def
+++ b/lib/fuzzer/FuzzerExtFunctions.def
@@ -16,12 +16,12 @@
// Optional user functions
EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false);
EXT_FUNC(LLVMFuzzerCustomMutator, size_t,
- (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed),
+ (uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed),
false);
EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
- (const uint8_t * Data1, size_t Size1,
- const uint8_t * Data2, size_t Size2,
- uint8_t * Out, size_t MaxOutSize, unsigned int Seed),
+ (const uint8_t *Data1, size_t Size1,
+ const uint8_t *Data2, size_t Size2,
+ uint8_t *Out, size_t MaxOutSize, unsigned int Seed),
false);
// Sanitizer functions
@@ -33,8 +33,9 @@ EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
(void (*malloc_hook)(const volatile void *, size_t),
void (*free_hook)(const volatile void *)),
false);
+EXT_FUNC(__sanitizer_log_write, void, (const char *buf, size_t len), false);
EXT_FUNC(__sanitizer_purge_allocator, void, (), false);
-EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t, size_t), false);
+EXT_FUNC(__sanitizer_print_memory_profile, void, (size_t, size_t), false);
EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
EXT_FUNC(__sanitizer_symbolize_pc, void,
(void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
index a11cfe4405f3..0e19a9cde6ca 100644
--- a/lib/fuzzer/FuzzerFlags.def
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -123,9 +123,6 @@ FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
-FUZZER_FLAG_INT(lazy_counters, 0, "If 1, a performance optimization is"
- "enabled for the 8bit inline counters. "
- "Requires that libFuzzer successfully installs its SEGV handler")
FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
"if 2, close stderr; if 3, close both. "
"Be careful, this will also close e.g. stderr of asan.")
diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h
index f2a4c437de38..31096ce804bc 100644
--- a/lib/fuzzer/FuzzerInternal.h
+++ b/lib/fuzzer/FuzzerInternal.h
@@ -98,7 +98,8 @@ private:
void ReportNewCoverage(InputInfo *II, const Unit &U);
void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
- void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0);
+ void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0,
+ size_t Features = 0);
void PrintStatusForNewUnit(const Unit &U, const char *Text);
void CheckExitOnSrcPosOrItem();
diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp
index f773f9a13398..451a4c173167 100644
--- a/lib/fuzzer/FuzzerLoop.cpp
+++ b/lib/fuzzer/FuzzerLoop.cpp
@@ -273,9 +273,9 @@ void Fuzzer::InterruptCallback() {
NO_SANITIZE_MEMORY
void Fuzzer::AlarmCallback() {
assert(Options.UnitTimeoutSec > 0);
- // In Windows Alarm callback is executed by a different thread.
+ // In Windows and Fuchsia, Alarm callback is executed by a different thread.
// NetBSD's current behavior needs this change too.
-#if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD
+#if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA
if (!InFuzzingThread())
return;
#endif
@@ -319,14 +319,15 @@ void Fuzzer::RssLimitCallback() {
_Exit(Options.OOMExitCode); // Stop right now.
}
-void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
+void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units,
+ size_t Features) {
size_t ExecPerSec = execPerSec();
if (!Options.Verbosity)
return;
Printf("#%zd\t%s", TotalNumberOfRuns, Where);
if (size_t N = TPC.GetTotalPCCoverage())
Printf(" cov: %zd", N);
- if (size_t N = Corpus.NumFeatures())
+ if (size_t N = Features ? Features : Corpus.NumFeatures())
Printf(" ft: %zd", N);
if (!Corpus.empty()) {
Printf(" corp: %zd", Corpus.NumActiveUnits());
@@ -512,10 +513,12 @@ size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
}
void Fuzzer::CrashOnOverwrittenData() {
- Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n",
+ Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n",
GetPid());
+ PrintStackTrace();
+ Printf("SUMMARY: libFuzzer: overwrites-const-input\n");
DumpCurrentUnit("crash-");
- Printf("SUMMARY: libFuzzer: out-of-memory\n");
+ PrintFinalStats();
_Exit(Options.ErrorExitCode); // Stop right now.
}
@@ -739,10 +742,6 @@ void Fuzzer::ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles) {
uint8_t dummy = 0;
ExecuteCallback(&dummy, 0);
- // Protect lazy counters here, after the once-init code has been executed.
- if (Options.LazyCounters)
- TPC.ProtectLazyCounters();
-
if (CorporaFiles.empty()) {
Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
Unit U({'\n'}); // Valid ASCII input.
diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp
index 75b2b5d59b9c..e3ad8b3851e7 100644
--- a/lib/fuzzer/FuzzerMerge.cpp
+++ b/lib/fuzzer/FuzzerMerge.cpp
@@ -19,6 +19,7 @@
#include <iterator>
#include <set>
#include <sstream>
+#include <unordered_set>
namespace fuzzer {
@@ -210,6 +211,9 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
Set<size_t> AllFeatures;
+ auto PrintStatsWrapper = [this, &AllFeatures](const char* Where) {
+ this->PrintStats(Where, "\n", 0, AllFeatures.size());
+ };
Set<const TracePC::PCTableEntry *> AllPCs;
for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
Fuzzer::MaybeExitGracefully();
@@ -218,7 +222,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
U.resize(MaxInputLen);
U.shrink_to_fit();
}
- std::ostringstream StartedLine;
+
// Write the pre-run marker.
OF << "STARTED " << i << " " << U.size() << "\n";
OF.flush(); // Flush is important since Command::Execute may crash.
@@ -238,7 +242,9 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
TPC.UpdateObservedPCs();
// Show stats.
if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
- PrintStats("pulse ");
+ PrintStatsWrapper("pulse ");
+ if (TotalNumberOfRuns == M.NumFilesInFirstCorpus)
+ PrintStatsWrapper("LOADED");
// Write the post-run marker and the coverage.
OF << "FT " << i;
for (size_t F : UniqFeatures)
@@ -252,25 +258,42 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
OF << "\n";
OF.flush();
}
- PrintStats("DONE ");
+ PrintStatsWrapper("DONE ");
}
-static void WriteNewControlFile(const std::string &CFPath,
- const Vector<SizedFile> &OldCorpus,
- const Vector<SizedFile> &NewCorpus) {
- RemoveFile(CFPath);
- std::ofstream ControlFile(CFPath);
- ControlFile << (OldCorpus.size() + NewCorpus.size()) << "\n";
- ControlFile << OldCorpus.size() << "\n";
+static size_t WriteNewControlFile(const std::string &CFPath,
+ const Vector<SizedFile> &OldCorpus,
+ const Vector<SizedFile> &NewCorpus,
+ const Vector<MergeFileInfo> &KnownFiles) {
+ std::unordered_set<std::string> FilesToSkip;
+ for (auto &SF: KnownFiles)
+ FilesToSkip.insert(SF.Name);
+
+ Vector<std::string> FilesToUse;
+ auto MaybeUseFile = [=, &FilesToUse](std::string Name) {
+ if (FilesToSkip.find(Name) == FilesToSkip.end())
+ FilesToUse.push_back(Name);
+ };
for (auto &SF: OldCorpus)
- ControlFile << SF.File << "\n";
+ MaybeUseFile(SF.File);
+ auto FilesToUseFromOldCorpus = FilesToUse.size();
for (auto &SF: NewCorpus)
- ControlFile << SF.File << "\n";
+ MaybeUseFile(SF.File);
+
+ RemoveFile(CFPath);
+ std::ofstream ControlFile(CFPath);
+ ControlFile << FilesToUse.size() << "\n";
+ ControlFile << FilesToUseFromOldCorpus << "\n";
+ for (auto &FN: FilesToUse)
+ ControlFile << FN << "\n";
+
if (!ControlFile) {
Printf("MERGE-OUTER: failed to write to the control file: %s\n",
CFPath.c_str());
exit(1);
}
+
+ return FilesToUse.size();
}
// Outer process. Does not call the target code and thus should not fail.
@@ -286,12 +309,13 @@ void CrashResistantMerge(const Vector<std::string> &Args,
bool V /*Verbose*/) {
if (NewCorpus.empty() && OldCorpus.empty()) return; // Nothing to merge.
size_t NumAttempts = 0;
+ Vector<MergeFileInfo> KnownFiles;
if (FileSize(CFPath)) {
VPrintf(V, "MERGE-OUTER: non-empty control file provided: '%s'\n",
CFPath.c_str());
Merger M;
std::ifstream IF(CFPath);
- if (M.Parse(IF, /*ParseCoverage=*/false)) {
+ if (M.Parse(IF, /*ParseCoverage=*/true)) {
VPrintf(V, "MERGE-OUTER: control file ok, %zd files total,"
" first not processed file %zd\n",
M.Files.size(), M.FirstNotProcessedFile);
@@ -300,12 +324,25 @@ void CrashResistantMerge(const Vector<std::string> &Args,
"(merge has stumbled on it the last time)\n",
M.LastFailure.c_str());
if (M.FirstNotProcessedFile >= M.Files.size()) {
+ // Merge has already been completed with the given merge control file.
+ if (M.Files.size() == OldCorpus.size() + NewCorpus.size()) {
+ VPrintf(
+ V,
+ "MERGE-OUTER: nothing to do, merge has been completed before\n");
+ exit(0);
+ }
+
+ // Number of input files likely changed, start merge from scratch, but
+ // reuse coverage information from the given merge control file.
VPrintf(
- V, "MERGE-OUTER: nothing to do, merge has been completed before\n");
- exit(0);
+ V,
+ "MERGE-OUTER: starting merge from scratch, but reusing coverage "
+ "information from the given control file\n");
+ KnownFiles = M.Files;
+ } else {
+ // There is a merge in progress, continue.
+ NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
}
-
- NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
} else {
VPrintf(V, "MERGE-OUTER: bad control file, will overwrite it\n");
}
@@ -313,10 +350,11 @@ void CrashResistantMerge(const Vector<std::string> &Args,
if (!NumAttempts) {
// The supplied control file is empty or bad, create a fresh one.
- NumAttempts = OldCorpus.size() + NewCorpus.size();
- VPrintf(V, "MERGE-OUTER: %zd files, %zd in the initial corpus\n",
- NumAttempts, OldCorpus.size());
- WriteNewControlFile(CFPath, OldCorpus, NewCorpus);
+ VPrintf(V, "MERGE-OUTER: "
+ "%zd files, %zd in the initial corpus, %zd processed earlier\n",
+ OldCorpus.size() + NewCorpus.size(), OldCorpus.size(),
+ KnownFiles.size());
+ NumAttempts = WriteNewControlFile(CFPath, OldCorpus, NewCorpus, KnownFiles);
}
// Execute the inner process until it passes.
@@ -353,6 +391,8 @@ void CrashResistantMerge(const Vector<std::string> &Args,
VPrintf(V,
"MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb());
+
+ M.Files.insert(M.Files.end(), KnownFiles.begin(), KnownFiles.end());
M.Merge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles);
VPrintf(V, "MERGE-OUTER: %zd new files with %zd new features added; "
"%zd new coverage edges\n",
diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h
index ad3df015bc77..beecc980380b 100644
--- a/lib/fuzzer/FuzzerOptions.h
+++ b/lib/fuzzer/FuzzerOptions.h
@@ -75,7 +75,6 @@ struct FuzzingOptions {
bool HandleXfsz = false;
bool HandleUsr1 = false;
bool HandleUsr2 = false;
- bool LazyCounters = false;
};
} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp
index 4a1308de5504..f03be7a39502 100644
--- a/lib/fuzzer/FuzzerTracePC.cpp
+++ b/lib/fuzzer/FuzzerTracePC.cpp
@@ -67,45 +67,6 @@ void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
NumInline8bitCounters += M.Size();
}
-// Mark all full page counter regions as PROT_NONE and set Enabled=false.
-// The first time the instrumented code hits such a protected/disabled
-// counter region we should catch a SEGV and call UnprotectLazyCounters,
-// which will mark the page as PROT_READ|PROT_WRITE and set Enabled=true.
-//
-// Whenever other functions iterate over the counters they should ignore
-// regions with Enabled=false.
-void TracePC::ProtectLazyCounters() {
- size_t NumPagesProtected = 0;
- IterateCounterRegions([&](Module::Region &R) {
- if (!R.OneFullPage) return;
- if (Mprotect(R.Start, R.Stop - R.Start, false)) {
- R.Enabled = false;
- NumPagesProtected++;
- }
- });
- if (NumPagesProtected)
- Printf("INFO: %zd pages of counters where protected;"
- " libFuzzer's SEGV handler must be installed\n",
- NumPagesProtected);
-}
-
-bool TracePC::UnprotectLazyCounters(void *CounterPtr) {
- // Printf("UnprotectLazyCounters: %p\n", CounterPtr);
- if (!CounterPtr)
- return false;
- bool Done = false;
- uint8_t *Addr = reinterpret_cast<uint8_t *>(CounterPtr);
- IterateCounterRegions([&](Module::Region &R) {
- if (!R.OneFullPage || R.Enabled || Done) return;
- if (Addr >= R.Start && Addr < R.Stop)
- if (Mprotect(R.Start, R.Stop - R.Start, true)) {
- R.Enabled = true;
- Done = true;
- }
- });
- return Done;
-}
-
void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
@@ -173,7 +134,7 @@ inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
}
/// \return the address of the next instruction.
-/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cc`
+/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cpp`
ALWAYS_INLINE uintptr_t TracePC::GetNextInstructionPc(uintptr_t PC) {
#if defined(__mips__)
return PC + 8;
diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h
index 4f5ebeb047a1..501f3b544971 100644
--- a/lib/fuzzer/FuzzerTracePC.h
+++ b/lib/fuzzer/FuzzerTracePC.h
@@ -119,9 +119,6 @@ class TracePC {
void SetFocusFunction(const std::string &FuncName);
bool ObservedFocusFunction();
- void ProtectLazyCounters();
- bool UnprotectLazyCounters(void *CounterPtr);
-
struct PCTableEntry {
uintptr_t PC, PCFlags;
};
diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h
index 0a127911df3c..85c5571d684f 100644
--- a/lib/fuzzer/FuzzerUtil.h
+++ b/lib/fuzzer/FuzzerUtil.h
@@ -52,8 +52,6 @@ void SetSignalHandler(const FuzzingOptions& Options);
void SleepSeconds(int Seconds);
-bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite);
-
unsigned long GetPid();
size_t GetPeakRSSMb();
diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp
index 1f04b33c154e..79fd950bbf97 100644
--- a/lib/fuzzer/FuzzerUtilFuchsia.cpp
+++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -305,12 +305,19 @@ void CrashHandler(zx_handle_t *Event) {
} // namespace
-bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
- return false; // UNIMPLEMENTED
-}
-
// Platform specific functions.
void SetSignalHandler(const FuzzingOptions &Options) {
+ // Make sure information from libFuzzer and the sanitizers are easy to
+ // reassemble. `__sanitizer_log_write` has the added benefit of ensuring the
+ // DSO map is always available for the symbolizer.
+ // A uint64_t fits in 20 chars, so 64 is plenty.
+ char Buf[64];
+ memset(Buf, 0, sizeof(Buf));
+ snprintf(Buf, sizeof(Buf), "==%lu== INFO: libFuzzer starting.\n", GetPid());
+ if (EF->__sanitizer_log_write)
+ __sanitizer_log_write(Buf, sizeof(Buf));
+ Printf("%s", Buf);
+
// Set up alarm handler if needed.
if (Options.UnitTimeoutSec > 0) {
std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
@@ -400,13 +407,14 @@ int ExecuteCommand(const Command &Cmd) {
// that lacks a mutable working directory. Fortunately, when this is the case
// a mutable output directory must be specified using "-artifact_prefix=...",
// so write the log file(s) there.
+ // However, we don't want to apply this logic for absolute paths.
int FdOut = STDOUT_FILENO;
if (Cmd.hasOutputFile()) {
- std::string Path;
- if (Cmd.hasFlag("artifact_prefix"))
- Path = Cmd.getFlagValue("artifact_prefix") + "/" + Cmd.getOutputFile();
- else
- Path = Cmd.getOutputFile();
+ std::string Path = Cmd.getOutputFile();
+ bool IsAbsolutePath = Path.length() > 1 && Path[0] == '/';
+ if (!IsAbsolutePath && Cmd.hasFlag("artifact_prefix"))
+ Path = Cmd.getFlagValue("artifact_prefix") + "/" + Path;
+
FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
if (FdOut == -1) {
Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(),
diff --git a/lib/fuzzer/FuzzerUtilPosix.cpp b/lib/fuzzer/FuzzerUtilPosix.cpp
index 110785d87413..cefe7ae181e7 100644
--- a/lib/fuzzer/FuzzerUtilPosix.cpp
+++ b/lib/fuzzer/FuzzerUtilPosix.cpp
@@ -37,7 +37,6 @@ static void (*upstream_segv_handler)(int, siginfo_t *, void *);
static void SegvHandler(int sig, siginfo_t *si, void *ucontext) {
assert(si->si_signo == SIGSEGV);
- if (TPC.UnprotectLazyCounters(si->si_addr)) return;
if (upstream_segv_handler)
return upstream_segv_handler(sig, si, ucontext);
Fuzzer::StaticCrashSignalCallback();
@@ -98,11 +97,6 @@ void SetTimer(int Seconds) {
SetSigaction(SIGALRM, AlarmHandler);
}
-bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
- return 0 == mprotect(Ptr, Size,
- AllowReadWrite ? (PROT_READ | PROT_WRITE) : PROT_NONE);
-}
-
void SetSignalHandler(const FuzzingOptions& Options) {
if (Options.UnitTimeoutSec > 0)
SetTimer(Options.UnitTimeoutSec / 2 + 1);
diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp
index 074e1eb42309..ed90044c3f83 100644
--- a/lib/fuzzer/FuzzerUtilWindows.cpp
+++ b/lib/fuzzer/FuzzerUtilWindows.cpp
@@ -111,10 +111,6 @@ static TimerQ Timer;
static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
-bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
- return false; // UNIMPLEMENTED
-}
-
void SetSignalHandler(const FuzzingOptions& Options) {
HandlerOpt = &Options;
diff --git a/lib/fuzzer/utils/FuzzedDataProvider.h b/lib/fuzzer/utils/FuzzedDataProvider.h
deleted file mode 100644
index 1b5b4bb01269..000000000000
--- a/lib/fuzzer/utils/FuzzedDataProvider.h
+++ /dev/null
@@ -1,245 +0,0 @@
-//===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// A single header library providing an utility class to break up an array of
-// bytes. Whenever run on the same input, provides the same output, as long as
-// its methods are called in the same order, with the same arguments.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
-#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
-
-#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <cstring>
-#include <initializer_list>
-#include <string>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-class FuzzedDataProvider {
-public:
- // |data| is an array of length |size| that the FuzzedDataProvider wraps to
- // provide more granular access. |data| must outlive the FuzzedDataProvider.
- FuzzedDataProvider(const uint8_t *data, size_t size)
- : data_ptr_(data), remaining_bytes_(size) {}
- ~FuzzedDataProvider() = default;
-
- // Returns a std::vector containing |num_bytes| of input data. If fewer than
- // |num_bytes| of data remain, returns a shorter std::vector containing all
- // of the data that's left. Can be used with any byte sized type, such as
- // char, unsigned char, uint8_t, etc.
- template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- return ConsumeBytes<T>(num_bytes, num_bytes);
- }
-
- // Similar to |ConsumeBytes|, but also appends the terminator value at the end
- // of the resulting vector. Useful, when a mutable null-terminated C-string is
- // needed, for example. But that is a rare case. Better avoid it, if possible,
- // and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
- template <typename T>
- std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes,
- T terminator = 0) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
- result.back() = terminator;
- return result;
- }
-
- // Returns a std::string containing |num_bytes| of input data. Using this and
- // |.c_str()| on the resulting string is the best way to get an immutable
- // null-terminated C string. If fewer than |num_bytes| of data remain, returns
- // a shorter std::string containing all of the data that's left.
- std::string ConsumeBytesAsString(size_t num_bytes) {
- static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
- "ConsumeBytesAsString cannot convert the data to a string.");
-
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::string result(
- reinterpret_cast<const std::string::value_type *>(data_ptr_),
- num_bytes);
- Advance(num_bytes);
- return result;
- }
-
- // Returns a number in the range [min, max] by consuming bytes from the
- // input data. The value might not be uniformly distributed in the given
- // range. If there's no input data left, always returns |min|. |min| must
- // be less than or equal to |max|.
- template <typename T> T ConsumeIntegralInRange(T min, T max) {
- static_assert(std::is_integral<T>::value, "An integral type is required.");
- static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
-
- if (min > max)
- abort();
-
- // Use the biggest type possible to hold the range and the result.
- uint64_t range = static_cast<uint64_t>(max) - min;
- uint64_t result = 0;
- size_t offset = 0;
-
- while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
- remaining_bytes_ != 0) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // |ConsumeBytes|. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- --remaining_bytes_;
- result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
- offset += CHAR_BIT;
- }
-
- // Avoid division by 0, in case |range + 1| results in overflow.
- if (range != std::numeric_limits<decltype(range)>::max())
- result = result % (range + 1);
-
- return static_cast<T>(min + result);
- }
-
- // Returns a std::string of length from 0 to |max_length|. When it runs out of
- // input data, returns what remains of the input. Designed to be more stable
- // with respect to a fuzzer inserting characters than just picking a random
- // length and then consuming that many bytes with |ConsumeBytes|.
- std::string ConsumeRandomLengthString(size_t max_length) {
- // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
- // followed by anything else to the end of the string. As a result of this
- // logic, a fuzzer can insert characters into the string, and the string
- // will be lengthened to include those new characters, resulting in a more
- // stable fuzzer than picking the length of a string independently from
- // picking its contents.
- std::string result;
-
- // Reserve the anticipated capaticity to prevent several reallocations.
- result.reserve(std::min(max_length, remaining_bytes_));
- for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
- char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next == '\\' && remaining_bytes_ != 0) {
- next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next != '\\')
- break;
- }
- result += next;
- }
-
- result.shrink_to_fit();
- return result;
- }
-
- // Returns a std::vector containing all remaining bytes of the input data.
- template <typename T> std::vector<T> ConsumeRemainingBytes() {
- return ConsumeBytes<T>(remaining_bytes_);
- }
-
- // Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
- // object.
- // Returns a std::vector containing all remaining bytes of the input data.
- std::string ConsumeRemainingBytesAsString() {
- return ConsumeBytesAsString(remaining_bytes_);
- }
-
- // Returns a number in the range [Type's min, Type's max]. The value might
- // not be uniformly distributed in the given range. If there's no input data
- // left, always returns |min|.
- template <typename T> T ConsumeIntegral() {
- return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
- std::numeric_limits<T>::max());
- }
-
- // Reads one byte and returns a bool, or false when no data remains.
- bool ConsumeBool() { return 1 & ConsumeIntegral<uint8_t>(); }
-
- // Returns a copy of a value selected from a fixed-size |array|.
- template <typename T, size_t size>
- T PickValueInArray(const T (&array)[size]) {
- static_assert(size > 0, "The array must be non empty.");
- return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
- }
-
- template <typename T>
- T PickValueInArray(std::initializer_list<const T> list) {
- // static_assert(list.size() > 0, "The array must be non empty.");
- return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
- }
-
- // Return an enum value. The enum must start at 0 and be contiguous. It must
- // also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
- // enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
- template <typename T> T ConsumeEnum() {
- static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
- return static_cast<T>(ConsumeIntegralInRange<uint32_t>(
- 0, static_cast<uint32_t>(T::kMaxValue)));
- }
-
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_bytes_; }
-
-private:
- FuzzedDataProvider(const FuzzedDataProvider &) = delete;
- FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
-
- void Advance(size_t num_bytes) {
- if (num_bytes > remaining_bytes_)
- abort();
-
- data_ptr_ += num_bytes;
- remaining_bytes_ -= num_bytes;
- }
-
- template <typename T>
- std::vector<T> ConsumeBytes(size_t size, size_t num_bytes_to_consume) {
- static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
-
- // The point of using the size-based constructor below is to increase the
- // odds of having a vector object with capacity being equal to the length.
- // That part is always implementation specific, but at least both libc++ and
- // libstdc++ allocate the requested number of bytes in that constructor,
- // which seems to be a natural choice for other implementations as well.
- // To increase the odds even more, we also call |shrink_to_fit| below.
- std::vector<T> result(size);
- std::memcpy(result.data(), data_ptr_, num_bytes_to_consume);
- Advance(num_bytes_to_consume);
-
- // Even though |shrink_to_fit| is also implementation specific, we expect it
- // to provide an additional assurance in case vector's constructor allocated
- // a buffer which is larger than the actual amount of data we put inside it.
- result.shrink_to_fit();
- return result;
- }
-
- template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value) {
- static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
- static_assert(!std::numeric_limits<TU>::is_signed,
- "Source type must be unsigned.");
-
- // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
- if (std::numeric_limits<TS>::is_modulo)
- return static_cast<TS>(value);
-
- // Avoid using implementation-defined unsigned to signer conversions.
- // To learn more, see https://stackoverflow.com/questions/13150449.
- if (value <= std::numeric_limits<TS>::max())
- return static_cast<TS>(value);
- else {
- constexpr auto TS_min = std::numeric_limits<TS>::min();
- return TS_min + static_cast<char>(value - TS_min);
- }
- }
-
- const uint8_t *data_ptr_;
- size_t remaining_bytes_;
-};
-
-#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_