summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSergey Matveev <earthdok@google.com>2013-05-29 13:09:44 +0000
committerSergey Matveev <earthdok@google.com>2013-05-29 13:09:44 +0000
commit12d01bac1c09a8412546e71485a3cba2d416c0fc (patch)
tree807250144ec4522606300e9bbbad45456fff02a6 /lib
parent4c086441ff9d06e53fa941671781008d453dba49 (diff)
[asan] Make ASan report the correct thread address ranges to LSan.
This CL enables thread support in LSan when used on top of ASan. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@182854 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/asan/asan_rtl.cc2
-rw-r--r--lib/asan/asan_thread.cc34
-rw-r--r--lib/asan/asan_thread.h8
-rw-r--r--lib/asan/lit_tests/unpoison_tls.cc40
4 files changed, 74 insertions, 10 deletions
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index f989c5c0d..b0cf702a5 100644
--- a/lib/asan/asan_rtl.cc
+++ b/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/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index da2838103..0787e9337 100644
--- a/lib/asan/asan_thread.cc
+++ b/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/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 14062b62f..bf08818da 100644
--- a/lib/asan/asan_thread.h
+++ b/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/lib/asan/lit_tests/unpoison_tls.cc b/lib/asan/lit_tests/unpoison_tls.cc
new file mode 100644
index 000000000..d2fc580be
--- /dev/null
+++ b/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 <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <sanitizer/asan_interface.h>
+
+__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;
+}