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,48 @@ typedef InternalMmapVector Frontier; +#if CAN_SANITIZE_LEAKS +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; +#else +typedef int AllocatorCache; +#endif // CAN_SANITIZE_LEAKS + +const u32 kInvalidTid = (u32) -1; + +struct LsanThread { + int init; + int disable_counter; + u32 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 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,7 +245,7 @@ if (flags()->use_tls) { LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end); - if (cache_begin == cache_end) { + if (cache_begin == cache_end || cache_begin >= tls_end || cache_end <= tls_begin) { ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); } else { // Because LSan should not be loaded with dlopen(), we can assume 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; @@ -51,8 +52,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,11 @@ #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,13 +38,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.tid = kInvalidTid; + tls.init = 1; + } + + return &tls; } +#endif // SANITIZER_ANDROID + ThreadContext::ThreadContext(int tid) : ThreadContextBase(tid), @@ -101,15 +125,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 +154,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,22 @@ 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; + +#if defined(__get_tls) +INLINE void **AndroidGetTls() { return &__get_tls()[TLS_SLOT_TSAN];} +#else +INLINE void **AndroidGetTls() { return nullptr;} +#endif + +#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 Index: sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- sanitizer_common/sanitizer_platform_limits_posix.h +++ sanitizer_common/sanitizer_platform_limits_posix.h @@ -53,9 +53,10 @@ #if !SANITIZER_ANDROID extern unsigned struct_statfs_sz; extern unsigned struct_sockaddr_sz; - extern unsigned ucontext_t_sz; #endif // !SANITIZER_ANDROID + extern unsigned ucontext_t_sz; + #if SANITIZER_LINUX #if defined(__x86_64__) @@ -174,13 +175,16 @@ }; #endif +#if SANITIZER_LINUX + extern unsigned struct_rlimit64_sz; +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID struct __sanitizer_mallinfo { int v[10]; }; extern unsigned struct_ustat_sz; - extern unsigned struct_rlimit64_sz; extern unsigned struct_statvfs64_sz; struct __sanitizer_ipc_perm { Index: sanitizer_common/sanitizer_platform_limits_posix.cc =================================================================== --- sanitizer_common/sanitizer_platform_limits_posix.cc +++ sanitizer_common/sanitizer_platform_limits_posix.cc @@ -232,9 +232,10 @@ #if !SANITIZER_ANDROID unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); - unsigned ucontext_t_sz = sizeof(ucontext_t); #endif // !SANITIZER_ANDROID +unsigned ucontext_t_sz = sizeof(ucontext_t); + #if SANITIZER_LINUX unsigned struct_epoll_event_sz = sizeof(struct epoll_event); unsigned struct_sysinfo_sz = sizeof(struct sysinfo); @@ -255,10 +256,13 @@ #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned struct_ustat_sz = sizeof(struct ustat); - unsigned struct_rlimit64_sz = sizeof(struct rlimit64); unsigned struct_statvfs64_sz = sizeof(struct statvfs64); #endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_LINUX + unsigned struct_rlimit64_sz = sizeof(struct rlimit64); +#endif // SANITIZER_LINUX + #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned struct_timex_sz = sizeof(struct timex); unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);