diff options
author | Kostya Serebryany <kcc@google.com> | 2014-09-23 17:59:53 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@gcc.gnu.org> | 2014-09-23 17:59:53 +0000 |
commit | 866e32ad336f1698809cc03c48f884379d6b39e0 (patch) | |
tree | dfe8acd36f160811afc54c8eaf16e8160ba8bd70 /libsanitizer/lsan | |
parent | e8ee40544aef309d4225852dda191bf0f986f761 (diff) | |
download | gcc-866e32ad336f1698809cc03c48f884379d6b39e0.zip gcc-866e32ad336f1698809cc03c48f884379d6b39e0.tar.gz gcc-866e32ad336f1698809cc03c48f884379d6b39e0.tar.bz2 |
[libsanitizer merge from upstream r218156]
From-SVN: r215527
Diffstat (limited to 'libsanitizer/lsan')
-rw-r--r-- | libsanitizer/lsan/lsan.cc | 21 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan.h | 20 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan_allocator.cc | 42 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan_allocator.h | 2 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan_common.cc | 63 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan_common.h | 6 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan_interceptors.cc | 37 | ||||
-rw-r--r-- | libsanitizer/lsan/lsan_preinit.cc | 6 |
8 files changed, 115 insertions, 82 deletions
diff --git a/libsanitizer/lsan/lsan.cc b/libsanitizer/lsan/lsan.cc index c1481f5..61792d9 100644 --- a/libsanitizer/lsan/lsan.cc +++ b/libsanitizer/lsan/lsan.cc @@ -23,16 +23,6 @@ bool lsan_init_is_running; namespace __lsan { -static void InitializeCommonFlags() { - CommonFlags *cf = common_flags(); - SetCommonFlagsDefaults(cf); - cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); - cf->malloc_context_size = 30; - cf->detect_leaks = true; - - ParseCommonFlagsFromString(cf, GetEnv("LSAN_OPTIONS")); -} - ///// Interface to the common LSan module. ///// bool WordIsPoisoned(uptr addr) { return false; @@ -48,7 +38,7 @@ extern "C" void __lsan_init() { return; lsan_init_is_running = true; SanitizerToolName = "LeakSanitizer"; - InitializeCommonFlags(); + InitCommonLsan(true); InitializeAllocator(); InitTlsSize(); InitializeInterceptors(); @@ -58,11 +48,14 @@ extern "C" void __lsan_init() { ThreadStart(tid, GetTid()); SetCurrentThread(tid); - Symbolizer::Init(common_flags()->external_symbolizer_path); - - InitCommonLsan(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) Atexit(DoLeakCheck); lsan_inited = true; lsan_init_is_running = false; } + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_print_stack_trace() { + GET_STACK_TRACE_FATAL; + stack.Print(); +} diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h index 8a5030c..57888e3 100644 --- a/libsanitizer/lsan/lsan.h +++ b/libsanitizer/lsan/lsan.h @@ -13,6 +13,26 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" +#define GET_STACK_TRACE(max_size, fast) \ + StackTrace stack; \ + { \ + uptr stack_top = 0, stack_bottom = 0; \ + ThreadContext *t; \ + if (fast && (t = CurrentThreadContext())) { \ + stack_top = t->stack_end(); \ + stack_bottom = t->stack_begin(); \ + } \ + stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ + /* context */ 0, stack_top, stack_bottom, fast); \ + } + +#define GET_STACK_TRACE_FATAL \ + GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) + +#define GET_STACK_TRACE_MALLOC \ + GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \ + common_flags()->fast_unwind_on_malloc) + namespace __lsan { void InitializeInterceptors(); diff --git a/libsanitizer/lsan/lsan_allocator.cc b/libsanitizer/lsan/lsan_allocator.cc index 3e81ebe..cda2b86 100644 --- a/libsanitizer/lsan/lsan_allocator.cc +++ b/libsanitizer/lsan/lsan_allocator.cc @@ -13,6 +13,7 @@ #include "lsan_allocator.h" #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" @@ -51,7 +52,7 @@ void AllocatorThreadFinish() { allocator.SwallowCache(&cache); } -static ChunkMetadata *Metadata(void *p) { +static ChunkMetadata *Metadata(const void *p) { return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p)); } @@ -85,10 +86,12 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); RegisterAllocation(stack, p, size); + if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size); return p; } void Deallocate(void *p) { + if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RegisterDeallocation(p); allocator.Deallocate(&cache, p); } @@ -111,7 +114,7 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end) { *end = *begin + sizeof(cache); } -uptr GetMallocUsableSize(void *p) { +uptr GetMallocUsableSize(const void *p) { ChunkMetadata *m = Metadata(p); if (!m) return 0; return m->requested_size; @@ -198,3 +201,38 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) { } } } // namespace __lsan + +using namespace __lsan; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_current_allocated_bytes() { + uptr stats[AllocatorStatCount]; + allocator.GetStats(stats); + return stats[AllocatorStatAllocated]; +} + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_heap_size() { + uptr stats[AllocatorStatCount]; + allocator.GetStats(stats); + return stats[AllocatorStatMapped]; +} + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_free_bytes() { return 0; } + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_unmapped_bytes() { return 0; } + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; } + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_allocated_size(const void *p) { + return GetMallocUsableSize(p); +} +} // extern "C" diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h index 61ea865..aae0d28 100644 --- a/libsanitizer/lsan/lsan_allocator.h +++ b/libsanitizer/lsan/lsan_allocator.h @@ -23,7 +23,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, void Deallocate(void *p); void *Reallocate(const StackTrace &stack, void *p, uptr new_size, uptr alignment); -uptr GetMallocUsableSize(void *p); +uptr GetMallocUsableSize(const void *p); template<typename Callable> void ForEachChunk(const Callable &callback); diff --git a/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc index 78afa77..e340b89 100644 --- a/libsanitizer/lsan/lsan_common.cc +++ b/libsanitizer/lsan/lsan_common.cc @@ -34,15 +34,13 @@ bool DisabledInThisThread() { return disable_counter > 0; } Flags lsan_flags; -static void InitializeFlags() { +static void InitializeFlags(bool standalone) { Flags *f = flags(); // Default values. f->report_objects = false; f->resolution = 0; f->max_leaks = 0; f->exitcode = 23; - f->print_suppressions = true; - f->suppressions=""; f->use_registers = true; f->use_globals = true; f->use_stacks = true; @@ -70,9 +68,18 @@ static void InitializeFlags() { ParseFlag(options, &f->log_pointers, "log_pointers", ""); ParseFlag(options, &f->log_threads, "log_threads", ""); ParseFlag(options, &f->exitcode, "exitcode", ""); - ParseFlag(options, &f->print_suppressions, "print_suppressions", ""); - ParseFlag(options, &f->suppressions, "suppressions", ""); } + + // Set defaults for common flags (only in standalone mode) and parse + // them from LSAN_OPTIONS. + CommonFlags *cf = common_flags(); + if (standalone) { + SetCommonFlagsDefaults(cf); + cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); + cf->malloc_context_size = 30; + cf->detect_leaks = true; + } + ParseCommonFlagsFromString(cf, options); } #define LOG_POINTERS(...) \ @@ -85,24 +92,14 @@ static void InitializeFlags() { if (flags()->log_threads) Report(__VA_ARGS__); \ } while (0); -SuppressionContext *suppression_ctx; +static bool suppressions_inited = false; void InitializeSuppressions() { - CHECK(!suppression_ctx); - ALIGNED(64) static char placeholder[sizeof(SuppressionContext)]; - suppression_ctx = new(placeholder) SuppressionContext; - char *suppressions_from_file; - uptr buffer_size; - if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file, - &buffer_size, 1 << 26 /* max_len */)) - suppression_ctx->Parse(suppressions_from_file); - if (flags()->suppressions[0] && !buffer_size) { - Printf("LeakSanitizer: failed to read suppressions file '%s'\n", - flags()->suppressions); - Die(); - } + CHECK(!suppressions_inited); + SuppressionContext::InitIfNecessary(); if (&__lsan_default_suppressions) - suppression_ctx->Parse(__lsan_default_suppressions()); + SuppressionContext::Get()->Parse(__lsan_default_suppressions()); + suppressions_inited = true; } struct RootRegion { @@ -118,8 +115,8 @@ void InitializeRootRegions() { root_regions = new(placeholder) InternalMmapVector<RootRegion>(1); } -void InitCommonLsan() { - InitializeFlags(); +void InitCommonLsan(bool standalone) { + InitializeFlags(standalone); InitializeRootRegions(); if (common_flags()->detect_leaks) { // Initialization which can fail or print warnings should only be done if @@ -129,9 +126,9 @@ void InitCommonLsan() { } } -class Decorator: private __sanitizer::AnsiColorDecorator { +class Decorator: public __sanitizer::SanitizerCommonDecorator { public: - Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { } + Decorator() : SanitizerCommonDecorator() { } const char *Error() { return Red(); } const char *Leak() { return Blue(); } const char *End() { return Default(); } @@ -387,7 +384,7 @@ static void CollectLeaksCb(uptr chunk, void *arg) { static void PrintMatchedSuppressions() { InternalMmapVector<Suppression *> matched(1); - suppression_ctx->GetMatched(&matched); + SuppressionContext::Get()->GetMatched(&matched); if (!matched.size()) return; const char *line = "-----------------------------------------------------"; @@ -448,7 +445,7 @@ void DoLeakCheck() { Printf("%s", d.End()); param.leak_report.ReportTopLeaks(flags()->max_leaks); } - if (flags()->print_suppressions) + if (common_flags()->print_suppressions) PrintMatchedSuppressions(); if (unsuppressed_count > 0) { param.leak_report.PrintSummary(); @@ -463,20 +460,22 @@ static Suppression *GetSuppressionForAddr(uptr addr) { // Suppress by module name. const char *module_name; uptr module_offset; - if (Symbolizer::Get()->GetModuleNameAndOffsetForPC(addr, &module_name, - &module_offset) && - suppression_ctx->Match(module_name, SuppressionLeak, &s)) + if (Symbolizer::GetOrInit() + ->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) && + SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s)) return s; // Suppress by file or function name. static const uptr kMaxAddrFrames = 16; InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames); for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo(); - uptr addr_frames_num = Symbolizer::Get()->SymbolizePC( + uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC( addr, addr_frames.data(), kMaxAddrFrames); for (uptr i = 0; i < addr_frames_num; i++) { - if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) || - suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s)) + if (SuppressionContext::Get()->Match(addr_frames[i].function, + SuppressionLeak, &s) || + SuppressionContext::Get()->Match(addr_frames[i].file, SuppressionLeak, + &s)) return s; } return 0; diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h index 0c84d41..72523d9f 100644 --- a/libsanitizer/lsan/lsan_common.h +++ b/libsanitizer/lsan/lsan_common.h @@ -49,10 +49,6 @@ struct Flags { int max_leaks; // If nonzero kill the process with this exit code upon finding leaks. int exitcode; - // Print matched suppressions after leak checking. - bool print_suppressions; - // Suppressions file name. - const char* suppressions; // Flags controlling the root set of reachable memory. // Global variables (.data and .bss). @@ -133,7 +129,7 @@ enum IgnoreObjectResult { }; // Functions called from the parent tool. -void InitCommonLsan(); +void InitCommonLsan(bool standalone); void DoLeakCheck(); bool DisabledInThisThread(); diff --git a/libsanitizer/lsan/lsan_interceptors.cc b/libsanitizer/lsan/lsan_interceptors.cc index dfaad32..ac05dfa 100644 --- a/libsanitizer/lsan/lsan_interceptors.cc +++ b/libsanitizer/lsan/lsan_interceptors.cc @@ -32,21 +32,6 @@ int pthread_key_create(unsigned *key, void (*destructor)(void* v)); int pthread_setspecific(unsigned key, const void *v); } -#define GET_STACK_TRACE \ - StackTrace stack; \ - { \ - uptr stack_top = 0, stack_bottom = 0; \ - ThreadContext *t; \ - bool fast = common_flags()->fast_unwind_on_malloc; \ - if (fast && (t = CurrentThreadContext())) { \ - stack_top = t->stack_end(); \ - stack_bottom = t->stack_begin(); \ - } \ - stack.Unwind(__sanitizer::common_flags()->malloc_context_size, \ - StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), 0, \ - stack_top, stack_bottom, fast); \ - } - #define ENSURE_LSAN_INITED do { \ CHECK(!lsan_init_is_running); \ if (!lsan_inited) \ @@ -63,7 +48,7 @@ namespace std { INTERCEPTOR(void*, malloc, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; return Allocate(stack, size, 1, kAlwaysClearMemory); } @@ -86,26 +71,32 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { } if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0; ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; size *= nmemb; return Allocate(stack, size, 1, true); } INTERCEPTOR(void*, realloc, void *q, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; return Reallocate(stack, q, size, 1); } INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; + return Allocate(stack, size, alignment, kAlwaysClearMemory); +} + +INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { + ENSURE_LSAN_INITED; + GET_STACK_TRACE_MALLOC; return Allocate(stack, size, alignment, kAlwaysClearMemory); } INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory); // FIXME: Return ENOMEM if user requested more than max alloc size. return 0; @@ -113,7 +104,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { INTERCEPTOR(void*, valloc, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; if (size == 0) size = GetPageSizeCached(); return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); @@ -140,7 +131,7 @@ INTERCEPTOR(int, mallopt, int cmd, int value) { INTERCEPTOR(void*, pvalloc, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; uptr PageSize = GetPageSizeCached(); size = RoundUpTo(size, PageSize); if (size == 0) { @@ -154,7 +145,7 @@ INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free)); #define OPERATOR_NEW_BODY \ ENSURE_LSAN_INITED; \ - GET_STACK_TRACE; \ + GET_STACK_TRACE_MALLOC; \ return Allocate(stack, size, 1, kAlwaysClearMemory); INTERCEPTOR_ATTRIBUTE diff --git a/libsanitizer/lsan/lsan_preinit.cc b/libsanitizer/lsan/lsan_preinit.cc index 856f9f7..d1efd31 100644 --- a/libsanitizer/lsan/lsan_preinit.cc +++ b/libsanitizer/lsan/lsan_preinit.cc @@ -12,11 +12,7 @@ #include "lsan.h" -#ifndef LSAN_USE_PREINIT_ARRAY -#define LSAN_USE_PREINIT_ARRAY 1 -#endif - -#if LSAN_USE_PREINIT_ARRAY && !defined(PIC) +#if SANITIZER_CAN_USE_PREINIT_ARRAY // We force __lsan_init to be called before anyone else by placing it into // .preinit_array section. __attribute__((section(".preinit_array"), used)) |