From 09886cd17ab8e5e601fda0e2aa21ff28c1a8fa63 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 29 May 2013 13:09:44 +0000 Subject: [PATCH] [asan] Make ASan report the correct thread address ranges to LSan. This CL enables thread support in LSan when used on top of ASan. llvm-svn: 182854 --- compiler-rt/lib/asan/asan_rtl.cc | 2 + compiler-rt/lib/asan/asan_thread.cc | 34 ++++++++++++---- compiler-rt/lib/asan/asan_thread.h | 8 +++- .../lib/asan/lit_tests/unpoison_tls.cc | 40 +++++++++++++++++++ 4 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 compiler-rt/lib/asan/lit_tests/unpoison_tls.cc diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index f989c5c0d2a5..b0cf702a5ee0 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -547,6 +547,8 @@ void __asan_init() { asan_inited = 1; asan_init_is_running = false; + InitTlsSize(); + // Create main thread. AsanTSDInit(AsanThread::TSDDtor); AsanThread *main_thread = AsanThread::Create(0, 0); diff --git a/compiler-rt/lib/asan/asan_thread.cc b/compiler-rt/lib/asan/asan_thread.cc index da28381031a5..0787e933789d 100644 --- a/compiler-rt/lib/asan/asan_thread.cc +++ b/compiler-rt/lib/asan/asan_thread.cc @@ -100,17 +100,17 @@ void AsanThread::Destroy() { // We also clear the shadow on thread destruction because // some code may still be executing in later TSD destructors // and we don't want it to have any poisoned stack. - ClearShadowForThreadStack(); + ClearShadowForThreadStackAndTLS(); fake_stack().Cleanup(); uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); UnmapOrDie(this, size); } void AsanThread::Init() { - SetThreadStackTopAndBottom(); + SetThreadStackAndTls(); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); - ClearShadowForThreadStack(); + ClearShadowForThreadStackAndTLS(); if (flags()->verbosity >= 1) { int local = 0; Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n", @@ -143,14 +143,21 @@ thread_return_t AsanThread::ThreadStart(uptr os_id) { return res; } -void AsanThread::SetThreadStackTopAndBottom() { - GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_); +void AsanThread::SetThreadStackAndTls() { + uptr stack_size = 0, tls_size = 0; + GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_, + &tls_size); + stack_top_ = stack_bottom_ + stack_size; + tls_end_ = tls_begin_ + tls_size; + int local; CHECK(AddrIsInStack((uptr)&local)); } -void AsanThread::ClearShadowForThreadStack() { +void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); + if (tls_begin_ != tls_end_) + PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); } const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset, @@ -251,8 +258,19 @@ 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) { - // FIXME: Stub. - return false; + __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( + __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); + if (!context) return false; + __asan::AsanThread *t = context->thread; + if (!t) return false; + *stack_begin = t->stack_bottom(); + *stack_end = t->stack_top(); + *tls_begin = t->tls_begin(); + *tls_end = t->tls_end(); + // ASan doesn't keep allocator caches in TLS, so these are unused. + *cache_begin = 0; + *cache_end = 0; + return true; } void LockThreadRegistry() { diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index 14062b62f751..bf08818da043 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -63,6 +63,8 @@ class AsanThread { uptr stack_top() { return stack_top_; } uptr stack_bottom() { return stack_bottom_; } uptr stack_size() { return stack_top_ - stack_bottom_; } + uptr tls_begin() { return tls_begin_; } + uptr tls_end() { return tls_end_; } u32 tid() { return context_->tid; } AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } @@ -79,13 +81,15 @@ class AsanThread { private: AsanThread() {} - void SetThreadStackTopAndBottom(); - void ClearShadowForThreadStack(); + void SetThreadStackAndTls(); + void ClearShadowForThreadStackAndTLS(); AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; uptr stack_top_; uptr stack_bottom_; + uptr tls_begin_; + uptr tls_end_; FakeStack fake_stack_; AsanThreadLocalMallocStorage malloc_storage_; diff --git a/compiler-rt/lib/asan/lit_tests/unpoison_tls.cc b/compiler-rt/lib/asan/lit_tests/unpoison_tls.cc new file mode 100644 index 000000000000..d2fc580be082 --- /dev/null +++ b/compiler-rt/lib/asan/lit_tests/unpoison_tls.cc @@ -0,0 +1,40 @@ +// Test that TLS is unpoisoned on thread death. +// REQUIRES: x86_64-supported-target,i386-supported-target + +// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/dlclose-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 +// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/dlclose-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 + +#include +#include +#include + +#include + +__thread int64_t tls_var[2]; + +volatile int64_t *p_tls_var; + +void *first(void *arg) { + ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var)); + p_tls_var = tls_var; + return 0; +} + +void *second(void *arg) { + assert(tls_var == p_tls_var); + *p_tls_var = 1; + return 0; +} + +int main(int argc, char *argv[]) { + pthread_t p; + assert(0 == pthread_create(&p, 0, first, 0)); + assert(0 == pthread_join(p, 0)); + assert(0 == pthread_create(&p, 0, second, 0)); + assert(0 == pthread_join(p, 0)); + return 0; +}