From 1a1c8bea2d0a3c5d51792e33349decda0ae2d655 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 7 Jun 2016 23:32:50 +0000 Subject: [PATCH] [LibFuzzer] Declare and use sanitizer functions in ``fuzzer::ExternalFunctions`` This fixes linking problems on OSX. Unfortunately it turns out we need to use an instance of the ``fuzzer::ExternalFunctions`` object in several places so this commit also replaces all instances with a single global instance. It also turns out initializing a global ``fuzzer::ExternalFunctions`` before main is entered (i.e. letting the object be initialised by the global initializers) is not safe (on OSX the call to ``Printf()`` in the CTOR crashes if it is called from a global initializer) so we instead have a global ``fuzzer::ExternalFunctions*`` and initialize it inside ``FuzzerDriver()``. Multiple unit tests depend also depend on the ``fuzzer::ExternalFunctions*`` global so a ``main()`` function has been added that initializes it before running any tests. Differential Revision: http://reviews.llvm.org/D20943 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@272072 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerDriver.cpp | 10 ++-- lib/Fuzzer/FuzzerExtFunctions.def | 16 +++++- lib/Fuzzer/FuzzerExtFunctions.h | 5 +- lib/Fuzzer/FuzzerIO.cpp | 9 ++-- lib/Fuzzer/FuzzerInternal.h | 10 ++-- lib/Fuzzer/FuzzerLoop.cpp | 78 +++++++++++------------------- lib/Fuzzer/FuzzerMutate.cpp | 8 +-- lib/Fuzzer/test/FuzzerUnittest.cpp | 21 ++++++++ 8 files changed, 84 insertions(+), 73 deletions(-) diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index 9807d605aeb..4e980bfd807 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -269,9 +269,9 @@ static bool AllInputsAreFiles() { int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { using namespace fuzzer; assert(argc && argv && "Argument pointers cannot be nullptr"); - fuzzer::ExternalFunctions EF; - if (EF.LLVMFuzzerInitialize) - EF.LLVMFuzzerInitialize(argc, argv); + EF = new ExternalFunctions(); + if (EF->LLVMFuzzerInitialize) + EF->LLVMFuzzerInitialize(argc, argv); const std::vector Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); @@ -422,4 +422,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { exit(0); // Don't let F destroy itself. } + +// Storage for global ExternalFunctions object. +ExternalFunctions *EF = nullptr; + } // namespace fuzzer diff --git a/lib/Fuzzer/FuzzerExtFunctions.def b/lib/Fuzzer/FuzzerExtFunctions.def index dccec18f479..2810a0046e3 100644 --- a/lib/Fuzzer/FuzzerExtFunctions.def +++ b/lib/Fuzzer/FuzzerExtFunctions.def @@ -25,4 +25,18 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, uint8_t * Out, size_t MaxOutSize, unsigned int Seed), false); -// TODO: Sanitizer functions +// Sanitizer functions +EXT_FUNC(__lsan_enable, void, (), false); +EXT_FUNC(__lsan_disable, void, (), false); +EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); +EXT_FUNC(__sanitizer_get_coverage_pc_buffer, uintptr_t, (uintptr_t**), true); +EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false); +EXT_FUNC(__sanitizer_get_total_unique_caller_callee_pairs, size_t, (), false); +EXT_FUNC(__sanitizer_get_total_unique_coverage, size_t, (), true); +EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t), false); +EXT_FUNC(__sanitizer_print_stack_trace, void, (), true); +EXT_FUNC(__sanitizer_reset_coverage, void, (), true); +EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true); +EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); +EXT_FUNC(__sanitizer_update_counter_bitset_and_clear_counters, uintptr_t, + (uint8_t*), false); diff --git a/lib/Fuzzer/FuzzerExtFunctions.h b/lib/Fuzzer/FuzzerExtFunctions.h index 95b524027df..2ec86cb9231 100644 --- a/lib/Fuzzer/FuzzerExtFunctions.h +++ b/lib/Fuzzer/FuzzerExtFunctions.h @@ -17,8 +17,9 @@ namespace fuzzer { struct ExternalFunctions { - // Initialize function pointers. Functions that are not available - // will be set to nullptr. + // Initialize function pointers. Functions that are not available will be set + // to nullptr. Do not call this constructor before ``main()`` has been + // entered. ExternalFunctions(); #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ diff --git a/lib/Fuzzer/FuzzerIO.cpp b/lib/Fuzzer/FuzzerIO.cpp index 171b188eab5..0e0c4e989cc 100644 --- a/lib/Fuzzer/FuzzerIO.cpp +++ b/lib/Fuzzer/FuzzerIO.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// // IO functions. //===----------------------------------------------------------------------===// +#include "FuzzerExtFunctions.h" #include "FuzzerInternal.h" #include #include @@ -18,10 +19,6 @@ #include #include -extern "C" { -__attribute__((weak)) void __sanitizer_set_report_fd(void *); -} - namespace fuzzer { static FILE *OutputFile = stderr; @@ -126,8 +123,8 @@ void DupAndCloseStderr() { FILE *NewOutputFile = fdopen(OutputFd, "w"); if (NewOutputFile) { OutputFile = NewOutputFile; - if (__sanitizer_set_report_fd) - __sanitizer_set_report_fd(reinterpret_cast(OutputFd)); + if (EF->__sanitizer_set_report_fd) + EF->__sanitizer_set_report_fd(reinterpret_cast(OutputFd)); close(2); } } diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index ff1d1387ad0..6fb429e705e 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -279,9 +279,6 @@ private: size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, const std::vector &Mutators); - // Interface to functions that may or may not be available. - const ExternalFunctions EF; - Random &Rand; // Dictionary provided by the user via -dict=DICT_FILE. Dictionary ManualDictionary; @@ -483,12 +480,11 @@ private: // Need to know our own thread. static thread_local bool IsMyThread; - - // Interface to functions that may or may not be available. - // For future use, currently not used. - const ExternalFunctions EF; }; +// Global interface to functions that may or may not be available. +extern ExternalFunctions *EF; + }; // namespace fuzzer #endif // LLVM_FUZZER_INTERNAL_H diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index b7422329e05..5cfbad4c327 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -31,47 +31,23 @@ #endif #endif -extern "C" { -// Re-declare some of the sanitizer functions as "weak" so that -// libFuzzer can be linked w/o the sanitizers and sanitizer-coverage -// (in which case it will complain at start-up time). -__attribute__((weak)) void __sanitizer_print_stack_trace(); -__attribute__((weak)) void __sanitizer_reset_coverage(); -__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs(); -__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage(); -__attribute__((weak)) void -__sanitizer_set_death_callback(void (*callback)(void)); -__attribute__((weak)) size_t __sanitizer_get_number_of_counters(); -__attribute__((weak)) uintptr_t -__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); -__attribute__((weak)) uintptr_t -__sanitizer_get_coverage_pc_buffer(uintptr_t **data); - -__attribute__((weak)) void __sanitizer_malloc_hook(void *ptr, size_t size); -__attribute__((weak)) void __sanitizer_free_hook(void *ptr); -__attribute__((weak)) void __lsan_enable(); -__attribute__((weak)) void __lsan_disable(); -__attribute__((weak)) int __lsan_do_recoverable_leak_check(); -__attribute__((weak)) int __sanitizer_print_memory_profile(size_t); -} - namespace fuzzer { static const size_t kMaxUnitSizeToPrint = 256; static const size_t TruncateMaxRuns = 1000; thread_local bool Fuzzer::IsMyThread; -static void MissingWeakApiFunction(const char *FnName) { +static void MissingExternalApiFunction(const char *FnName) { Printf("ERROR: %s is not defined. Exiting.\n" "Did you use -fsanitize-coverage=... to build your code?\n", FnName); exit(1); } -#define CHECK_WEAK_API_FUNCTION(fn) \ +#define CHECK_EXTERNAL_FUNCTION(fn) \ do { \ - if (!fn) \ - MissingWeakApiFunction(#fn); \ + if (!(EF->fn)) \ + MissingExternalApiFunction(#fn); \ } while (false) // Only one Fuzzer per process. @@ -79,21 +55,21 @@ static Fuzzer *F; struct CoverageController { static void Reset() { - CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage); - __sanitizer_reset_coverage(); + CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage); + EF->__sanitizer_reset_coverage(); PcMapResetCurrent(); } static void ResetCounters(const Fuzzer::FuzzingOptions &Options) { if (Options.UseCounters) { - __sanitizer_update_counter_bitset_and_clear_counters(0); + EF->__sanitizer_update_counter_bitset_and_clear_counters(0); } } static void Prepare(const Fuzzer::FuzzingOptions &Options, Fuzzer::Coverage *C) { if (Options.UseCounters) { - size_t NumCounters = __sanitizer_get_number_of_counters(); + size_t NumCounters = EF->__sanitizer_get_number_of_counters(); C->CounterBitmap.resize(NumCounters); } } @@ -104,16 +80,16 @@ struct CoverageController { Fuzzer::Coverage *C) { bool Res = false; - uint64_t NewBlockCoverage = __sanitizer_get_total_unique_coverage(); + uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage(); if (NewBlockCoverage > C->BlockCoverage) { Res = true; C->BlockCoverage = NewBlockCoverage; } if (Options.UseIndirCalls && - __sanitizer_get_total_unique_caller_callee_pairs) { + EF->__sanitizer_get_total_unique_caller_callee_pairs) { uint64_t NewCallerCalleeCoverage = - __sanitizer_get_total_unique_caller_callee_pairs(); + EF->__sanitizer_get_total_unique_caller_callee_pairs(); if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) { Res = true; C->CallerCalleeCoverage = NewCallerCalleeCoverage; @@ -122,7 +98,7 @@ struct CoverageController { if (Options.UseCounters) { uint64_t CounterDelta = - __sanitizer_update_counter_bitset_and_clear_counters( + EF->__sanitizer_update_counter_bitset_and_clear_counters( C->CounterBitmap.data()); if (CounterDelta > 0) { Res = true; @@ -137,7 +113,8 @@ struct CoverageController { } uintptr_t *CoverageBuf; - uint64_t NewPcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf); + uint64_t NewPcBufferLen = + EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf); if (NewPcBufferLen > C->PcBufferLen) { Res = true; C->PcBufferLen = NewPcBufferLen; @@ -163,8 +140,8 @@ void Fuzzer::LazyAllocateCurrentUnitData() { } void Fuzzer::SetDeathCallback() { - CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback); - __sanitizer_set_death_callback(StaticDeathCallback); + CHECK_EXTERNAL_FUNCTION(__sanitizer_set_death_callback); + EF->__sanitizer_set_death_callback(StaticDeathCallback); } void Fuzzer::StaticDeathCallback() { @@ -206,8 +183,8 @@ void Fuzzer::StaticInterruptCallback() { void Fuzzer::CrashCallback() { Printf("==%d== ERROR: libFuzzer: deadly signal\n", GetPid()); - if (__sanitizer_print_stack_trace) - __sanitizer_print_stack_trace(); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" " Combine libFuzzer with AddressSanitizer or similar for better " "crash reports.\n"); @@ -242,8 +219,8 @@ void Fuzzer::AlarmCallback() { DumpCurrentUnit("timeout-"); Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), Seconds); - if (__sanitizer_print_stack_trace) - __sanitizer_print_stack_trace(); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); Printf("SUMMARY: libFuzzer: timeout\n"); PrintFinalStats(); _Exit(Options.TimeoutExitCode); // Stop right now. @@ -255,8 +232,8 @@ void Fuzzer::RssLimitCallback() { "==%d== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", GetPid(), GetPeakRSSMb(), Options.RssLimitMb); Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); - if (__sanitizer_print_memory_profile) - __sanitizer_print_memory_profile(50); + if (EF->__sanitizer_print_memory_profile) + EF->__sanitizer_print_memory_profile(50); DumpCurrentUnit("oom-"); Printf("SUMMARY: libFuzzer: out-of-memory\n"); PrintFinalStats(); @@ -422,7 +399,7 @@ bool Fuzzer::UpdateMaxCoverage() { if (Options.PrintNewCovPcs && PrevBufferLen != MaxCoverage.PcBufferLen) { uintptr_t *CoverageBuf; - __sanitizer_get_coverage_pc_buffer(&CoverageBuf); + EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf); assert(CoverageBuf); for (size_t I = PrevBufferLen; I < MaxCoverage.PcBufferLen; ++I) { Printf("%p\n", CoverageBuf[I]); @@ -651,13 +628,14 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, bool DuringInitialCorpusExecution) { if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. if (!Options.DetectLeaks) return; - if (!&__lsan_enable || !&__lsan_disable || !__lsan_do_recoverable_leak_check) + if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || + !(EF->__lsan_do_recoverable_leak_check)) return; // No lsan. // Run the target once again, but with lsan disabled so that if there is // a real leak we do not report it twice. - __lsan_disable(); + EF->__lsan_disable(); RunOne(Data, Size); - __lsan_enable(); + EF->__lsan_enable(); if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. if (NumberOfLeakDetectionAttempts++ > 1000) { Options.DetectLeaks = false; @@ -670,7 +648,7 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, } // Now perform the actual lsan pass. This is expensive and we must ensure // we don't call it too often. - if (__lsan_do_recoverable_leak_check()) { // Leak is found, report it. + if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. if (DuringInitialCorpusExecution) Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp index e25a00d84ac..bd82c0dee59 100644 --- a/lib/Fuzzer/FuzzerMutate.cpp +++ b/lib/Fuzzer/FuzzerMutate.cpp @@ -37,12 +37,12 @@ MutationDispatcher::MutationDispatcher(Random &Rand) : Rand(Rand) { "AddFromPersAutoDict"}, }); - if (EF.LLVMFuzzerCustomMutator) + if (EF->LLVMFuzzerCustomMutator) Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); else Mutators = DefaultMutators; - if (EF.LLVMFuzzerCustomCrossOver) + if (EF->LLVMFuzzerCustomCrossOver) Mutators.push_back( {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); } @@ -67,7 +67,7 @@ static char RandCh(Random &Rand) { size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize) { - return EF.LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); + return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); } size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, @@ -80,7 +80,7 @@ size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, return 0; MutateInPlaceHere.resize(MaxSize); auto &U = MutateInPlaceHere; - size_t NewSize = EF.LLVMFuzzerCustomCrossOver( + size_t NewSize = EF->LLVMFuzzerCustomCrossOver( Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); if (!NewSize) return 0; diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp index 7b49f2f08e4..91ac9a73c17 100644 --- a/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -3,6 +3,7 @@ #include "FuzzerInternal.h" #include "gtest/gtest.h" +#include #include using namespace fuzzer; @@ -14,6 +15,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { } TEST(Fuzzer, CrossOver) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); Unit A({0, 1, 2}), B({5, 6, 7}); @@ -82,6 +85,8 @@ typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, size_t MaxSize); void TestEraseByte(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -116,6 +121,8 @@ TEST(FuzzerMutate, EraseByte2) { } void TestInsertByte(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); int FoundMask = 0; @@ -150,6 +157,8 @@ TEST(FuzzerMutate, InsertByte2) { } void TestChangeByte(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); int FoundMask = 0; @@ -184,6 +193,8 @@ TEST(FuzzerMutate, ChangeByte2) { } void TestChangeBit(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); int FoundMask = 0; @@ -218,6 +229,8 @@ TEST(FuzzerMutate, ChangeBit2) { } void TestShuffleBytes(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); int FoundMask = 0; @@ -246,6 +259,8 @@ TEST(FuzzerMutate, ShuffleBytes2) { } void TestAddWordFromDictionary(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD}; @@ -286,6 +301,8 @@ TEST(FuzzerMutate, AddWordFromDictionary2) { } void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); uint8_t W[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF}; @@ -313,6 +330,8 @@ TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) { } void TestChangeASCIIInteger(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); @@ -405,6 +424,8 @@ TEST(FuzzerUtil, Base64) { } TEST(Corpus, Distribution) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); Random Rand(0); MutationDispatcher MD(Rand); Fuzzer::FuzzingOptions Options;