forked from OSchip/llvm-project
[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:
parent
89bcec8117
commit
09886cd17a
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue