Index: lsan/lsan.cc =================================================================== --- lsan/lsan.cc +++ lsan/lsan.cc @@ -82,13 +82,15 @@ u32 tid = ThreadCreate(0, 0, true); CHECK_EQ(tid, 0); ThreadStart(tid, GetTid()); - SetCurrentThread(tid); + GetCurrentThread()->tid = tid; if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) Atexit(DoLeakCheck); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); + AndroidLogInit(); + lsan_inited = true; lsan_init_is_running = false; } 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(&(GetCurrentThread()->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(&(GetCurrentThread()->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(&(GetCurrentThread()->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(&(GetCurrentThread()->cache), p); return nullptr; } - p = allocator.Reallocate(&cache, p, new_size, alignment); + p = allocator.Reallocate(&(GetCurrentThread()->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)&(GetCurrentThread()->cache); + *end = *begin + sizeof(GetCurrentThread()->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,36 @@ 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; + // 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 GetCurrentThread()->disable_counter > 0; } +void DisableInThisThread() { GetCurrentThread()->disable_counter++; } void EnableInThisThread() { - if (!disable_counter && common_flags()->detect_leaks) { + if (!(GetCurrentThread()->disable_counter) && common_flags()->detect_leaks) { Report("Unmatched call to __lsan_enable().\n"); Die(); } - disable_counter--; + GetCurrentThread()->disable_counter--; } Flags lsan_flags; @@ -244,6 +245,10 @@ if (flags()->use_tls) { LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end); + +#if SANITIZER_ANDROID + ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); +#else if (cache_begin == cache_end) { ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); } else { @@ -268,6 +273,7 @@ } } } +#endif } } } Index: lsan/lsan_interceptors.cc =================================================================== --- lsan/lsan_interceptors.cc +++ lsan/lsan_interceptors.cc @@ -220,7 +220,7 @@ int tid = 0; while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); - SetCurrentThread(tid); + GetCurrentThread()->tid = tid; ThreadStart(tid, GetTid()); atomic_store(&p->tid, 0, memory_order_release); return callback(param); @@ -252,7 +252,7 @@ res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); } if (res == 0) { - int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached); + int tid = ThreadCreate(GetCurrentThread()->tid, *(uptr *)th, detached); CHECK_NE(tid, 0); atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) 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; @@ -43,6 +44,13 @@ DTLS *dtls_; }; +struct LsanThread { + int init; + int disable_counter; + u32 tid; + AllocatorCache cache; +}; + void InitializeThreadRegistry(); void ThreadStart(u32 tid, uptr os_id); @@ -51,8 +59,7 @@ void ThreadJoin(u32 tid); u32 ThreadTid(uptr uid); -u32 GetCurrentThread(); -void SetCurrentThread(u32 tid); +LsanThread* GetCurrentThread(void); ThreadContext *CurrentThreadContext(); void EnsureMainThreadIDIsCorrect(); } // namespace __lsan Index: lsan/lsan_thread.cc =================================================================== --- lsan/lsan_thread.cc +++ lsan/lsan_thread.cc @@ -18,14 +18,21 @@ #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; +// From tsan_interceptors.cc in lieu of +#if SANITIZER_FREEBSD || SANITIZER_MAC +const int SIG_SETMASK = 3; +#elif defined(__mips__) +const int SIG_SETMASK = 3; +#else +const int SIG_SETMASK = 2; +#endif static ThreadRegistry *thread_registry; -static THREADLOCAL u32 current_thread_tid = kInvalidTid; static ThreadContextBase *CreateThreadContext(u32 tid) { void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); @@ -41,13 +48,40 @@ ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); } -u32 GetCurrentThread() { - return current_thread_tid; + +#if SANITIZER_ANDROID +// Based on tsan_platform_linux.cc::cur_thread +LsanThread* GetCurrentThread(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->tid = kInvalidTid; + *(AndroidGetTls()) = tls; + } + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); + } + return tls; } +#else +static THREADLOCAL LsanThread tls; -void SetCurrentThread(u32 tid) { - current_thread_tid = tid; +LsanThread* GetCurrentThread(void) { + if (!tls.init) { + tls.current_thread_tid = kInvalidTid; + tls.init = 1; + } + + return &tls; } +#endif // SANITIZER_ANDROID + ThreadContext::ThreadContext(int tid) : ThreadContextBase(tid), @@ -101,15 +135,15 @@ } void ThreadFinish() { - thread_registry->FinishThread(GetCurrentThread()); + thread_registry->FinishThread(GetCurrentThread()->tid); } ThreadContext *CurrentThreadContext() { if (!thread_registry) return nullptr; - if (GetCurrentThread() == kInvalidTid) + if (GetCurrentThread()->tid == kInvalidTid) return nullptr; // No lock needed when getting current thread. - return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); + return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()->tid); } static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { @@ -130,7 +164,7 @@ } void EnsureMainThreadIDIsCorrect() { - if (GetCurrentThread() == 0) + if (GetCurrentThread()->tid == 0) CurrentThreadContext()->os_id = GetTid(); } Index: sanitizer_common/sanitizer_common.h =================================================================== --- sanitizer_common/sanitizer_common.h +++ sanitizer_common/sanitizer_common.h @@ -834,4 +834,19 @@ 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; }) +#endif + +static const int TLS_SLOT_TSAN = 8; + +INLINE void **AndroidGetTls() { return &__get_tls()[TLS_SLOT_TSAN];} +#endif // SANITIZER_ANDROID + + #endif // SANITIZER_COMMON_H Index: sanitizer_common/sanitizer_linux_libcdep.cc =================================================================== --- sanitizer_common/sanitizer_linux_libcdep.cc +++ sanitizer_common/sanitizer_linux_libcdep.cc @@ -366,8 +366,12 @@ *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]); } #elif SANITIZER_ANDROID - *addr = 0; - *size = 0; + // bionic_tls.h and limits.h + const int BIONIC_TLS_SLOTS = 9; + const int BIONIC_PTHREAD_KEY_COUNT = 141; + + *addr = (uptr) &(__get_tls()[BIONIC_TLS_SLOTS]); + *size = (BIONIC_PTHREAD_KEY_COUNT - BIONIC_TLS_SLOTS) * sizeof(void*); #else # error "Unknown OS" #endif