Index: lsan/lsan.cc =================================================================== --- lsan/lsan.cc +++ lsan/lsan.cc @@ -89,6 +89,8 @@ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); + AndroidLogInit(); + lsan_inited = true; lsan_init_is_running = false; } Index: lsan/lsan_allocator.h =================================================================== --- lsan/lsan_allocator.h +++ lsan/lsan_allocator.h @@ -17,6 +17,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" +#include "lsan_common.h" namespace __lsan { Index: lsan/lsan_allocator.cc =================================================================== --- lsan/lsan_allocator.cc +++ lsan/lsan_allocator.cc @@ -20,48 +20,21 @@ #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "lsan_common.h" +#include "lsan_thread.h" extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -struct ChunkMetadata { - u8 allocated : 8; // Must be first. - ChunkTag tag : 2; - uptr requested_size : 54; - u32 stack_trace_id; -}; - -#if defined(__mips64) || defined(__aarch64__) -static const uptr kMaxAllowedMallocSize = 4UL << 30; -static const uptr kRegionSizeLog = 20; -static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; -typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; -#else -static const uptr kMaxAllowedMallocSize = 8UL << 30; -static const uptr kAllocatorSpace = 0x600000000000ULL; -static const uptr kAllocatorSize = 0x40000000000ULL; // 4T. -typedef SizeClassAllocator64 PrimaryAllocator; -#endif -typedef SizeClassAllocatorLocalCache AllocatorCache; -typedef LargeMmapAllocator<> SecondaryAllocator; -typedef CombinedAllocator Allocator; static Allocator allocator; -static THREADLOCAL AllocatorCache cache; void InitializeAllocator() { allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null); } void AllocatorThreadFinish() { - allocator.SwallowCache(&cache); + allocator.SwallowCache(&(getCurrentTLS()->cache)); } static ChunkMetadata *Metadata(const void *p) { @@ -93,7 +66,7 @@ Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(&cache, size, alignment, false); + void *p = allocator.Allocate(&(getCurrentTLS()->cache), size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); @@ -107,7 +80,7 @@ if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); RegisterDeallocation(p); - allocator.Deallocate(&cache, p); + allocator.Deallocate(&(getCurrentTLS()->cache), p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, @@ -115,17 +88,17 @@ RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); - allocator.Deallocate(&cache, p); + allocator.Deallocate(&(getCurrentTLS()->cache), p); return nullptr; } - p = allocator.Reallocate(&cache, p, new_size, alignment); + p = allocator.Reallocate(&(getCurrentTLS()->cache), p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { - *begin = (uptr)&cache; - *end = *begin + sizeof(cache); + *begin = (uptr)&(getCurrentTLS()->cache); + *end = *begin + sizeof(getCurrentTLS()->cache); } uptr GetMallocUsableSize(const void *p) { Index: lsan/lsan_common.h =================================================================== --- lsan/lsan_common.h +++ lsan/lsan_common.h @@ -22,7 +22,7 @@ #include "sanitizer_common/sanitizer_stoptheworld.h" #include "sanitizer_common/sanitizer_symbolizer.h" -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \ +#if (SANITIZER_LINUX) && (SANITIZER_WORDSIZE == 64) \ && (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) #define CAN_SANITIZE_LEAKS 1 #else @@ -97,6 +97,45 @@ typedef InternalMmapVector Frontier; +struct ChunkMetadata { + u8 allocated : 8; // Must be first. + ChunkTag tag : 2; + uptr requested_size : 54; + u32 stack_trace_id; +}; + +#if defined(__mips64) || defined(__aarch64__) +static const uptr kMaxAllowedMallocSize = 4UL << 30; +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; +#else +static const uptr kMaxAllowedMallocSize = 8UL << 30; +static const uptr kAllocatorSpace = 0x600000000000ULL; +static const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +typedef SizeClassAllocator64 PrimaryAllocator; +#endif +typedef SizeClassAllocatorLocalCache AllocatorCache; +typedef LargeMmapAllocator<> SecondaryAllocator; +typedef CombinedAllocator Allocator; + +const u32 kInvalidTid = (u32) -1; + +typedef struct LsanThread LsanThread; + +struct LsanThread { + int init; + int disable_counter; + u32 current_thread_tid; + AllocatorCache cache; +}; + // Platform-specific functions. void InitializePlatformSpecificModules(); void ProcessGlobalRegions(Frontier *frontier); Index: lsan/lsan_common.cc =================================================================== --- lsan/lsan_common.cc +++ lsan/lsan_common.cc @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "lsan_common.h" +#include "lsan_allocator.h" +#include "lsan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" @@ -32,15 +34,14 @@ // also to protect the global list of root regions. BlockingMutex global_mutex(LINKER_INITIALIZED); -THREADLOCAL int disable_counter; -bool DisabledInThisThread() { return disable_counter > 0; } -void DisableInThisThread() { disable_counter++; } +bool DisabledInThisThread() { return getCurrentTLS()->disable_counter > 0; } +void DisableInThisThread() { getCurrentTLS()->disable_counter++; } void EnableInThisThread() { - if (!disable_counter && common_flags()->detect_leaks) { + if (!(getCurrentTLS()->disable_counter) && common_flags()->detect_leaks) { Report("Unmatched call to __lsan_enable().\n"); Die(); } - disable_counter--; + getCurrentTLS()->disable_counter--; } Flags lsan_flags; Index: lsan/lsan_flags.inc =================================================================== --- lsan/lsan_flags.inc +++ lsan/lsan_flags.inc @@ -30,8 +30,13 @@ "Root set: include global variables (.data and .bss)") LSAN_FLAG(bool, use_stacks, true, "Root set: include thread stacks") LSAN_FLAG(bool, use_registers, true, "Root set: include thread registers") +#if SANITIZER_ANDROID +LSAN_FLAG(bool, use_tls, false, + "Root set: include TLS and thread-specific storage") +#else LSAN_FLAG(bool, use_tls, true, "Root set: include TLS and thread-specific storage") +#endif // SANITIZER_ANDROID LSAN_FLAG(bool, use_root_regions, true, "Root set: include regions added via __lsan_register_root_region().") LSAN_FLAG(bool, use_ld_allocations, true, Index: lsan/lsan_thread.h =================================================================== --- lsan/lsan_thread.h +++ lsan/lsan_thread.h @@ -16,6 +16,7 @@ #define LSAN_THREAD_H #include "sanitizer_common/sanitizer_thread_registry.h" +#include "lsan_common.h" namespace __sanitizer { struct DTLS; @@ -51,6 +52,8 @@ void ThreadJoin(u32 tid); u32 ThreadTid(uptr uid); +LsanThread* getCurrentTLS(void); + u32 GetCurrentThread(); void SetCurrentThread(u32 tid); ThreadContext *CurrentThreadContext(); Index: lsan/lsan_thread.cc =================================================================== --- lsan/lsan_thread.cc +++ lsan/lsan_thread.cc @@ -12,20 +12,20 @@ // //===----------------------------------------------------------------------===// +#include + #include "lsan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#include "sanitizer_common/sanitizer_linux.h" #include "lsan_allocator.h" namespace __lsan { -const u32 kInvalidTid = (u32) -1; - static ThreadRegistry *thread_registry; -static THREADLOCAL u32 current_thread_tid = kInvalidTid; static ThreadContextBase *CreateThreadContext(u32 tid) { void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); @@ -41,12 +41,50 @@ ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); } + +#if !SANITIZER_ANDROID +static THREADLOCAL LsanThread tls; +#endif // !SANITIZER_ANDROID + + +#if SANITIZER_ANDROID +// Based on tsan_platform_linux.cc::cur_thread +LsanThread* getCurrentTLS(void) { + LsanThread* tls = (LsanThread*)(*AndroidGetTls()); + if (tls == nullptr) { + __sanitizer_sigset_t emptyset; + internal_sigfillset(&emptyset); + __sanitizer_sigset_t oldset; + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset)); + tls = reinterpret_cast(*AndroidGetTls()); + if (tls == nullptr) { + tls = reinterpret_cast(MmapOrDie(sizeof(LsanThread), + "LsanThread")); + tls->current_thread_tid = kInvalidTid; + *(AndroidGetTls()) = tls; + } + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); + } + return tls; +} +#else +LsanThread* getCurrentTLS(void) { + if (!tls.init) { + tls.current_thread_tid = kInvalidTid; + tls.init = 1; + } + + return &tls; +} +#endif // SANITIZER_ANDROID + + u32 GetCurrentThread() { - return current_thread_tid; + return getCurrentTLS()->current_thread_tid; } void SetCurrentThread(u32 tid) { - current_thread_tid = tid; + getCurrentTLS()->current_thread_tid = tid; } ThreadContext::ThreadContext(int tid) Index: sanitizer_common/sanitizer_common.h =================================================================== --- sanitizer_common/sanitizer_common.h +++ sanitizer_common/sanitizer_common.h @@ -834,4 +834,21 @@ uptr allocated; }; + +#if SANITIZER_ANDROID +// Voodoo from tsan +#if defined(__aarch64__) +# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; }) +#elif defined(__x86_64__) +# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; }) +#else +#error unsupported architecture +#endif + +static const int TLS_SLOT_TSAN = 8; + +void **AndroidGetTls(); +#endif // SANITIZER_ANDROID + + #endif // SANITIZER_COMMON_H Index: sanitizer_common/sanitizer_common.cc =================================================================== --- sanitizer_common/sanitizer_common.cc +++ sanitizer_common/sanitizer_common.cc @@ -490,3 +490,6 @@ return InstallMallocFreeHooks(malloc_hook, free_hook); } } // extern "C" + +void **AndroidGetTls() { return &__get_tls()[TLS_SLOT_TSAN];} +