[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
This commit is contained in:
Sergey Matveev 2013-05-29 13:09:44 +00:00
parent 89bcec8117
commit 09886cd17a
4 changed files with 74 additions and 10 deletions

View File

@ -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);

View File

@ -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() {

View File

@ -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_;

View File

@ -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;
}