From 1b2e8fb0ce651da2d47b98c33b29c0f42a080f13 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 8 May 2018 23:45:05 +0000 Subject: [libFuzzer] Guard symbolization with try-lock. Summary: When out-of-memory or timeout occurs, threads can be stopped during symbolization, thereby causing a deadlock when the OOM/TO handlers attempt symbolization. We avoid this deadlock by skipping symbolization if another thread is symbolizing. Reviewers: kcc Reviewed By: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D46605 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@331825 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 19 +++++++------------ lib/fuzzer/FuzzerUtil.cpp | 19 ++++++++++++++++++- lib/fuzzer/FuzzerUtil.h | 4 ++++ 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 6cc220d97..191556339 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -105,7 +105,7 @@ void MallocHook(const volatile void *ptr, size_t size) { return; Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); if (TraceLevel >= 2 && EF) - EF->__sanitizer_print_stack_trace(); + PrintStackTrace(); } } @@ -118,7 +118,7 @@ void FreeHook(const volatile void *ptr) { return; Printf("FREE[%zd] %p\n", N, ptr); if (TraceLevel >= 2 && EF) - EF->__sanitizer_print_stack_trace(); + PrintStackTrace(); } } @@ -129,8 +129,7 @@ void Fuzzer::HandleMalloc(size_t Size) { Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), Size); Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); + PrintStackTrace(); DumpCurrentUnit("oom-"); Printf("SUMMARY: libFuzzer: out-of-memory\n"); PrintFinalStats(); @@ -231,8 +230,7 @@ void Fuzzer::CrashCallback() { if (EF->__sanitizer_acquire_crash_state) EF->__sanitizer_acquire_crash_state(); Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); + PrintStackTrace(); Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" " Combine libFuzzer with AddressSanitizer or similar for better " "crash reports.\n"); @@ -249,8 +247,7 @@ void Fuzzer::ExitCallback() { !EF->__sanitizer_acquire_crash_state()) return; Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); + PrintStackTrace(); Printf("SUMMARY: libFuzzer: fuzz target exited\n"); DumpCurrentUnit("crash-"); PrintFinalStats(); @@ -296,8 +293,7 @@ void Fuzzer::AlarmCallback() { DumpCurrentUnit("timeout-"); Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), Seconds); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); + PrintStackTrace(); Printf("SUMMARY: libFuzzer: timeout\n"); PrintFinalStats(); _Exit(Options.TimeoutExitCode); // Stop right now. @@ -312,8 +308,7 @@ void Fuzzer::RssLimitCallback() { "==%lu== 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 (EF->__sanitizer_print_memory_profile) - EF->__sanitizer_print_memory_profile(95, 8); + PrintMemoryProfile(); DumpCurrentUnit("oom-"); Printf("SUMMARY: libFuzzer: out-of-memory\n"); PrintFinalStats(); diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp index 96b37d348..6286f9a71 100644 --- a/lib/fuzzer/FuzzerUtil.cpp +++ b/lib/fuzzer/FuzzerUtil.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -179,8 +180,12 @@ std::string Base64(const Unit &U) { return Res; } +static std::mutex SymbolizeMutex; + std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { - if (!EF->__sanitizer_symbolize_pc) return ""; + std::unique_lock l(SymbolizeMutex, std::try_to_lock); + if (!EF->__sanitizer_symbolize_pc || !l.owns_lock()) + return ""; char PcDescr[1024] = {}; EF->__sanitizer_symbolize_pc(reinterpret_cast(PC), SymbolizedFMT, PcDescr, sizeof(PcDescr)); @@ -195,6 +200,18 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { Printf(FallbackFMT, PC); } +void PrintStackTrace() { + std::unique_lock l(SymbolizeMutex, std::try_to_lock); + if (EF->__sanitizer_print_stack_trace && l.owns_lock()) + EF->__sanitizer_print_stack_trace(); +} + +void PrintMemoryProfile() { + std::unique_lock l(SymbolizeMutex, std::try_to_lock); + if (EF->__sanitizer_print_memory_profile && l.owns_lock()) + EF->__sanitizer_print_memory_profile(95, 8); +} + unsigned NumberOfCpuCores() { unsigned N = std::thread::hardware_concurrency(); if (!N) { diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h index f2ed028ce..8c5c57c3a 100644 --- a/lib/fuzzer/FuzzerUtil.h +++ b/lib/fuzzer/FuzzerUtil.h @@ -40,6 +40,10 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC); std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC); +void PrintStackTrace(); + +void PrintMemoryProfile(); + unsigned NumberOfCpuCores(); // Platform specific functions. -- cgit v1.2.3