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(__sanitizer_print_stack_trace, void, (), true); +EXT_FUNC(__sanitizer_reset_coverage, void, (), true); +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_set_death_callback, void, (void (*)(void)), false); +EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), true); +EXT_FUNC(__sanitizer_update_counter_bitset_and_clear_counters, uintptr_t, + (uint8_t*), true); +EXT_FUNC(__sanitizer_get_coverage_pc_buffer, uintptr_t, (uintptr_t**), true); +EXT_FUNC(__lsan_enable, void, (), false); +EXT_FUNC(__lsan_disable, void, (), false); +EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); +EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t), false); +EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); 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,9 @@ FILE *NewOutputFile = fdopen(OutputFd, "w"); if (NewOutputFile) { OutputFile = NewOutputFile; - if (__sanitizer_set_report_fd) - __sanitizer_set_report_fd(reinterpret_cast(OutputFd)); + fuzzer::ExternalFunctions EF; + if (EF.__sanitizer_set_report_fd) + EF.__sanitizer_set_report_fd(reinterpret_cast(OutputFd)); close(2); } } 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; @@ -70,7 +46,8 @@ #define CHECK_WEAK_API_FUNCTION(fn) \ do { \ - if (!fn) \ + /* FIXME: What a hack!*/ \ + if (!EF.fn) \ MissingWeakApiFunction(#fn); \ } while (false) @@ -78,22 +55,23 @@ static Fuzzer *F; struct CoverageController { - static void Reset() { + static void Reset(const ExternalFunctions &EF) { CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage); - __sanitizer_reset_coverage(); + EF.__sanitizer_reset_coverage(); PcMapResetCurrent(); } - static void ResetCounters(const Fuzzer::FuzzingOptions &Options) { + static void ResetCounters(const Fuzzer::FuzzingOptions &Options, + const ExternalFunctions &EF) { 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) { + Fuzzer::Coverage *C, const ExternalFunctions &EF) { if (Options.UseCounters) { - size_t NumCounters = __sanitizer_get_number_of_counters(); + size_t NumCounters = EF.__sanitizer_get_number_of_counters(); C->CounterBitmap.resize(NumCounters); } } @@ -101,19 +79,19 @@ // Records data to a maximum coverage tracker. Returns true if additional // coverage was discovered. static bool RecordMax(const Fuzzer::FuzzingOptions &Options, - Fuzzer::Coverage *C) { + Fuzzer::Coverage *C, const ExternalFunctions &EF) { 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 +100,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 +115,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; @@ -164,7 +143,7 @@ void Fuzzer::SetDeathCallback() { CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback); - __sanitizer_set_death_callback(StaticDeathCallback); + EF.__sanitizer_set_death_callback(StaticDeathCallback); } void Fuzzer::StaticDeathCallback() { @@ -206,8 +185,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 +221,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 +234,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(); @@ -417,11 +396,11 @@ bool Fuzzer::UpdateMaxCoverage() { uintptr_t PrevBufferLen = MaxCoverage.PcBufferLen; - bool Res = CoverageController::RecordMax(Options, &MaxCoverage); + bool Res = CoverageController::RecordMax(Options, &MaxCoverage, EF); 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]); @@ -435,7 +414,7 @@ TotalNumberOfRuns++; // TODO(aizatsky): this Reset call seems to be not needed. - CoverageController::ResetCounters(Options); + CoverageController::ResetCounters(Options, EF); ExecuteCallback(Data, Size); bool Res = UpdateMaxCoverage(); @@ -650,13 +629,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 +649,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"); @@ -723,9 +703,9 @@ } void Fuzzer::ResetCoverage() { - CoverageController::Reset(); + CoverageController::Reset(EF); MaxCoverage.Reset(); - CoverageController::Prepare(Options, &MaxCoverage); + CoverageController::Prepare(Options, &MaxCoverage, EF); } // Experimental search heuristic: drilling.