Index: lib/Fuzzer/FuzzerDriver.cpp =================================================================== --- lib/Fuzzer/FuzzerDriver.cpp +++ lib/Fuzzer/FuzzerDriver.cpp @@ -269,7 +269,9 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { using namespace fuzzer; assert(argc && argv && "Argument pointers cannot be nullptr"); - fuzzer::ExternalFunctions EF; + // We should have been called from main() so it should be safe + // to call Init() now. + EF.Init(); if (EF.LLVMFuzzerInitialize) EF.LLVMFuzzerInitialize(argc, argv); const std::vector Args(*argv, *argv + *argc); @@ -421,4 +423,8 @@ exit(0); // Don't let F destroy itself. } + +// Storage for global ExternalFunctions object. +ExternalFunctions EF; + } // namespace fuzzer Index: lib/Fuzzer/FuzzerExtFunctions.h =================================================================== --- lib/Fuzzer/FuzzerExtFunctions.h +++ lib/Fuzzer/FuzzerExtFunctions.h @@ -19,7 +19,8 @@ struct ExternalFunctions { // Initialize function pointers. Functions that are not available // will be set to nullptr. - ExternalFunctions(); + // Do not call this function before ``main()`` has been entered. + void Init(); #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ RETURN_TYPE(*NAME) FUNC_SIG = nullptr Index: lib/Fuzzer/FuzzerExtFunctions.def =================================================================== --- lib/Fuzzer/FuzzerExtFunctions.def +++ lib/Fuzzer/FuzzerExtFunctions.def @@ -20,4 +20,18 @@ (uint8_t * Data, size_t Size, size_t MaxSize, 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); Index: lib/Fuzzer/FuzzerExtFunctionsDlsym.cpp =================================================================== --- lib/Fuzzer/FuzzerExtFunctionsDlsym.cpp +++ lib/Fuzzer/FuzzerExtFunctionsDlsym.cpp @@ -37,7 +37,7 @@ namespace fuzzer { -ExternalFunctions::ExternalFunctions() { +void ExternalFunctions::Init() { #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ this->NAME = GetFnPtr(#NAME, WARN) Index: lib/Fuzzer/FuzzerExtFunctionsWeak.cpp =================================================================== --- lib/Fuzzer/FuzzerExtFunctionsWeak.cpp +++ lib/Fuzzer/FuzzerExtFunctionsWeak.cpp @@ -37,7 +37,7 @@ namespace fuzzer { -ExternalFunctions::ExternalFunctions() { +void ExternalFunctions::Init() { #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ this->NAME = ::NAME; \ CheckFnPtr((void *)::NAME, #NAME, WARN); Index: lib/Fuzzer/FuzzerIO.cpp =================================================================== --- lib/Fuzzer/FuzzerIO.cpp +++ 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 @@ 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); } } Index: lib/Fuzzer/FuzzerInternal.h =================================================================== --- lib/Fuzzer/FuzzerInternal.h +++ lib/Fuzzer/FuzzerInternal.h @@ -277,9 +277,6 @@ 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; @@ -480,12 +477,11 @@ // 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 Index: lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- lib/Fuzzer/FuzzerLoop.cpp +++ lib/Fuzzer/FuzzerLoop.cpp @@ -31,30 +31,6 @@ #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; @@ -68,9 +44,9 @@ exit(1); } -#define CHECK_WEAK_API_FUNCTION(fn) \ +#define CHECK_EXTERNAL_FUNCTION(fn) \ do { \ - if (!fn) \ + if (!EF.fn) \ MissingWeakApiFunction(#fn); \ } while (false) @@ -79,21 +55,21 @@ 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 @@ 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 @@ 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 @@ } 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::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::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 @@ 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 @@ "==%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(); @@ -421,7 +398,7 @@ 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]); @@ -650,13 +627,14 @@ 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; @@ -669,7 +647,7 @@ } // 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"); Index: lib/Fuzzer/test/FuzzerUnittest.cpp =================================================================== --- lib/Fuzzer/test/FuzzerUnittest.cpp +++ lib/Fuzzer/test/FuzzerUnittest.cpp @@ -406,6 +406,7 @@ TEST(Corpus, Distribution) { Random Rand(0); + fuzzer::EF.Init(); MutationDispatcher MD(Rand); Fuzzer::FuzzingOptions Options; Fuzzer Fuzz(LLVMFuzzerTestOneInput, MD, Options);