Index: lib/asan/asan_thread.h =================================================================== --- lib/asan/asan_thread.h +++ lib/asan/asan_thread.h @@ -23,6 +23,10 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_thread_registry.h" +namespace __sanitizer { +struct DTLS; +} // namespace __sanitizer + namespace __asan { const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits. @@ -67,6 +71,7 @@ uptr stack_size() { return stack_size_; } uptr tls_begin() { return tls_begin_; } uptr tls_end() { return tls_end_; } + DTLS *dtls() { return dtls_; } u32 tid() { return context_->tid; } AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } @@ -132,6 +137,7 @@ uptr stack_size_; uptr tls_begin_; uptr tls_end_; + DTLS *dtls_; FakeStack *fake_stack_; AsanThreadLocalMallocStorage malloc_storage_; Index: lib/asan/asan_thread.cc =================================================================== --- lib/asan/asan_thread.cc +++ lib/asan/asan_thread.cc @@ -199,6 +199,7 @@ &tls_size); stack_top_ = stack_bottom_ + stack_size_; tls_end_ = tls_begin_ + tls_size; + dtls_ = DTLS_Get(); int local; CHECK(AddrIsInStack((uptr)&local)); @@ -322,8 +323,8 @@ // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, - uptr *tls_begin, uptr *tls_end, - uptr *cache_begin, uptr *cache_end) { + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (!t) return false; *stack_begin = t->stack_bottom(); @@ -333,6 +334,7 @@ // ASan doesn't keep allocator caches in TLS, so these are unused. *cache_begin = 0; *cache_end = 0; + *dtls = t->dtls(); return true; } Index: lib/lsan/lsan.cc =================================================================== --- lib/lsan/lsan.cc +++ lib/lsan/lsan.cc @@ -43,6 +43,7 @@ cf.CopyFrom(*common_flags()); cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); cf.malloc_context_size = 30; + cf.intercept_tls_get_addr = true; cf.detect_leaks = true; cf.exitcode = 23; OverrideCommonFlags(cf); Index: lib/lsan/lsan_common.h =================================================================== --- lib/lsan/lsan_common.h +++ lib/lsan/lsan_common.h @@ -31,6 +31,7 @@ namespace __sanitizer { class FlagParser; +struct DTLS; } namespace __lsan { @@ -141,8 +142,8 @@ void LockThreadRegistry(); void UnlockThreadRegistry(); bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, - uptr *tls_begin, uptr *tls_end, - uptr *cache_begin, uptr *cache_end); + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls); void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, void *arg); // If called from the main thread, updates the main thread's TID in the thread Index: lib/lsan/lsan_common.cc =================================================================== --- lib/lsan/lsan_common.cc +++ lib/lsan/lsan_common.cc @@ -23,6 +23,7 @@ #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_tls_get_addr.h" #if CAN_SANITIZE_LEAKS namespace __lsan { @@ -185,9 +186,10 @@ uptr os_id = static_cast(suspended_threads.GetThreadID(i)); LOG_THREADS("Processing thread %d.\n", os_id); uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; + DTLS *dtls; bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin, &tls_end, - &cache_begin, &cache_end); + &cache_begin, &cache_end, &dtls); if (!thread_found) { // If a thread can't be found in the thread registry, it's probably in the // process of destruction. Log this event and move on. @@ -238,6 +240,17 @@ if (tls_end > cache_end) ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); } + if (dtls) { + for (uptr j = 0; j < dtls->dtv_size; ++j) { + uptr dtls_beg = dtls->dtv[j].beg; + uptr dtls_end = dtls_beg + dtls->dtv[j].size; + if (dtls_beg < dtls_end) { + LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end); + ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS", + kReachable); + } + } + } } } } Index: lib/lsan/lsan_interceptors.cc =================================================================== --- lib/lsan/lsan_interceptors.cc +++ lib/lsan/lsan_interceptors.cc @@ -20,6 +20,7 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" #include "lsan_thread.h" @@ -104,6 +105,14 @@ return 0; } +INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { + ENSURE_LSAN_INITED; + GET_STACK_TRACE_MALLOC; + void *res = Allocate(stack, size, alignment, kAlwaysClearMemory); + DTLS_on_libc_memalign(res, size); + return res; +} + INTERCEPTOR(void*, valloc, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; @@ -174,11 +183,6 @@ OPERATOR_DELETE_BODY; } -// We need this to intercept the __libc_memalign calls that are used to -// allocate dynamic TLS space in ld-linux.so. -INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s) - ALIAS(WRAPPER_NAME(memalign)); - ///// Thread initialization and finalization. ///// static unsigned g_thread_finalize_key; Index: lib/lsan/lsan_thread.h =================================================================== --- lib/lsan/lsan_thread.h +++ lib/lsan/lsan_thread.h @@ -17,6 +17,10 @@ #include "sanitizer_common/sanitizer_thread_registry.h" +namespace __sanitizer { +struct DTLS; +} + namespace __lsan { class ThreadContext : public ThreadContextBase { @@ -30,10 +34,13 @@ uptr tls_end() { return tls_end_; } uptr cache_begin() { return cache_begin_; } uptr cache_end() { return cache_end_; } + DTLS *dtls() { return dtls_; } + private: uptr stack_begin_, stack_end_, cache_begin_, cache_end_, tls_begin_, tls_end_; + DTLS *dtls_; }; void InitializeThreadRegistry(); Index: lib/lsan/lsan_thread.cc =================================================================== --- lib/lsan/lsan_thread.cc +++ lib/lsan/lsan_thread.cc @@ -17,6 +17,7 @@ #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 "lsan_allocator.h" namespace __lsan { @@ -49,18 +50,20 @@ } ThreadContext::ThreadContext(int tid) - : ThreadContextBase(tid), - stack_begin_(0), - stack_end_(0), - cache_begin_(0), - cache_end_(0), - tls_begin_(0), - tls_end_(0) {} + : ThreadContextBase(tid), + stack_begin_(0), + stack_end_(0), + cache_begin_(0), + cache_end_(0), + tls_begin_(0), + tls_end_(0), + dtls_(nullptr) {} struct OnStartedArgs { uptr stack_begin, stack_end, cache_begin, cache_end, tls_begin, tls_end; + DTLS *dtls; }; void ThreadContext::OnStarted(void *arg) { @@ -71,10 +74,12 @@ tls_end_ = args->tls_end; cache_begin_ = args->cache_begin; cache_end_ = args->cache_end; + dtls_ = args->dtls; } void ThreadContext::OnFinished() { AllocatorThreadFinish(); + DTLS_Destroy(); } u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { @@ -91,6 +96,7 @@ args.stack_end = args.stack_begin + stack_size; args.tls_end = args.tls_begin + tls_size; GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); + args.dtls = DTLS_Get(); thread_registry->StartThread(tid, os_id, &args); } @@ -131,8 +137,8 @@ ///// Interface to the common LSan module. ///// bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, - uptr *tls_begin, uptr *tls_end, - uptr *cache_begin, uptr *cache_end) { + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls) { ThreadContext *context = static_cast( thread_registry->FindThreadContextByOsIDLocked(os_id)); if (!context) return false; @@ -142,6 +148,7 @@ *tls_end = context->tls_end(); *cache_begin = context->cache_begin(); *cache_end = context->cache_end(); + *dtls = context->dtls(); return true; }