diff options
Diffstat (limited to 'lib/asan/asan_thread_registry.cc')
-rw-r--r-- | lib/asan/asan_thread_registry.cc | 157 |
1 files changed, 51 insertions, 106 deletions
diff --git a/lib/asan/asan_thread_registry.cc b/lib/asan/asan_thread_registry.cc index 39fba44..4540d58 100644 --- a/lib/asan/asan_thread_registry.cc +++ b/lib/asan/asan_thread_registry.cc @@ -1,4 +1,4 @@ -//===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===// +//===-- asan_thread_registry.cc -------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -16,8 +16,7 @@ #include "asan_stack.h" #include "asan_thread.h" #include "asan_thread_registry.h" - -#include <limits.h> +#include "sanitizer_common/sanitizer_common.h" namespace __asan { @@ -27,48 +26,6 @@ AsanThreadRegistry &asanThreadRegistry() { return asan_thread_registry; } -#ifdef ANDROID -#ifndef PTHREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_DESTRUCTOR_ITERATIONS 4 -#endif -#endif - -// Dark magic below. In order to be able to notice that we're not handling -// some thread creation routines (e.g. on Mac OS) we want to distinguish the -// thread that used to have a corresponding AsanThread object from the thread -// that never had one. That's why upon AsanThread destruction we set the -// pthread_key value to some odd number (that's not a valid pointer), instead -// of NULL. -// Because the TSD destructor for a non-NULL key value is called iteratively, -// we increase the value by two, keeping it an invalid pointer. -// Because the TSD implementations are allowed to call such a destructor -// infinitely (see -// http://pubs.opengroup.org/onlinepubs/009604499/functions/pthread_key_create.html -// ), we exit the program after a certain number of iterations. -static void DestroyAsanTsd(void *tsd) { - intptr_t iter = (intptr_t)tsd; - if (iter % 2 == 0) { - // The pointer is valid. - AsanThread *t = (AsanThread*)tsd; - if (t != asanThreadRegistry().GetMain()) { - delete t; - } - iter = 1; - } else { - // The pointer is invalid -- we've already destroyed the TSD before. - // If |iter| is too big, we're in the infinite loop. This should be - // impossible on the systems AddressSanitizer was tested on. - CHECK(iter < 4 * PTHREAD_DESTRUCTOR_ITERATIONS); - iter += 2; - } - CHECK(0 == pthread_setspecific(asanThreadRegistry().GetTlsKey(), - (void*)iter)); - if (FLAG_v >= 2) { - Report("DestroyAsanTsd: writing %p to the TSD slot of thread %p\n", - (void*)iter, pthread_self()); - } -} - AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) : main_thread_(x), main_thread_summary_(x), @@ -76,26 +33,25 @@ AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) mu_(x) { } void AsanThreadRegistry::Init() { - CHECK(0 == pthread_key_create(&tls_key_, DestroyAsanTsd)); - tls_key_created_ = true; - SetCurrent(&main_thread_); + AsanTSDInit(AsanThreadSummary::TSDDtor); main_thread_.set_summary(&main_thread_summary_); main_thread_summary_.set_thread(&main_thread_); - thread_summaries_[0] = &main_thread_summary_; - n_threads_ = 1; + RegisterThread(&main_thread_); + SetCurrent(&main_thread_); + // At this point only one thread exists. + inited_ = true; } -void AsanThreadRegistry::RegisterThread(AsanThread *thread, int parent_tid, - AsanStackTrace *stack) { +void AsanThreadRegistry::RegisterThread(AsanThread *thread) { ScopedLock lock(&mu_); - CHECK(n_threads_ > 0); - int tid = n_threads_; + u32 tid = n_threads_; n_threads_++; CHECK(n_threads_ < kMaxNumberOfThreads); - AsanThreadSummary *summary = new AsanThreadSummary(tid, parent_tid, stack); - summary->set_thread(thread); + + AsanThreadSummary *summary = thread->summary(); + CHECK(summary != 0); + summary->set_tid(tid); thread_summaries_[tid] = summary; - thread->set_summary(summary); } void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { @@ -103,7 +59,7 @@ void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { FlushToAccumulatedStatsUnlocked(&thread->stats()); AsanThreadSummary *summary = thread->summary(); CHECK(summary); - summary->set_thread(NULL); + summary->set_thread(0); } AsanThread *AsanThreadRegistry::GetMain() { @@ -111,45 +67,35 @@ AsanThread *AsanThreadRegistry::GetMain() { } AsanThread *AsanThreadRegistry::GetCurrent() { - CHECK(tls_key_created_); - AsanThread *thread = (AsanThread*)pthread_getspecific(tls_key_); - if ((!thread || (intptr_t)thread % 2) && FLAG_v >= 2) { - Report("GetCurrent: %p for thread %p\n", thread, pthread_self()); - } - if ((intptr_t)thread % 2) { - // Invalid pointer -- we've deleted the AsanThread already. Return NULL as - // if the TSD was empty. - // TODO(glider): if the code in the client TSD destructor calls - // pthread_create(), we'll set the parent tid of the spawned thread to NULL, - // although the creation stack will belong to the current thread. This may - // confuse the user, but is quite unlikely. - return NULL; - } else { - // NULL or valid pointer to AsanThread. - return thread; + AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); + if (!summary) { +#ifdef ANDROID + // On Android, libc constructor is called _after_ asan_init, and cleans up + // TSD. Try to figure out if this is still the main thread by the stack + // address. We are not entirely sure that we have correct main thread + // limits, so only do this magic on Android, and only if the found thread is + // the main thread. + AsanThread* thread = FindThreadByStackAddress((uptr)&summary); + if (thread && thread->tid() == 0) { + SetCurrent(thread); + return thread; + } +#endif + return 0; } + return summary->thread(); } void AsanThreadRegistry::SetCurrent(AsanThread *t) { - if (FLAG_v >=2) { - Report("SetCurrent: %p for thread %p\n", t, pthread_self()); + CHECK(t->summary()); + if (flags()->verbosity >= 2) { + Report("SetCurrent: %p for thread %p\n", + t->summary(), (void*)GetThreadSelf()); } // Make sure we do not reset the current AsanThread. - intptr_t old_key = (intptr_t)pthread_getspecific(tls_key_); - CHECK(!old_key || old_key % 2); - CHECK(0 == pthread_setspecific(tls_key_, t)); - CHECK(pthread_getspecific(tls_key_) == t); -} - -pthread_key_t AsanThreadRegistry::GetTlsKey() { - return tls_key_; -} - -// Returns true iff DestroyAsanTsd() was already called for this thread. -bool AsanThreadRegistry::IsCurrentThreadDying() { - CHECK(tls_key_created_); - intptr_t thread = (intptr_t)pthread_getspecific(tls_key_); - return (bool)(thread % 2); + CHECK(AsanTSDGet() == 0); + AsanTSDSet(t->summary()); + CHECK(AsanTSDGet() == t->summary()); } AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { @@ -163,19 +109,19 @@ AsanStats AsanThreadRegistry::GetAccumulatedStats() { return accumulated_stats_; } -size_t AsanThreadRegistry::GetCurrentAllocatedBytes() { +uptr AsanThreadRegistry::GetCurrentAllocatedBytes() { ScopedLock lock(&mu_); UpdateAccumulatedStatsUnlocked(); return accumulated_stats_.malloced - accumulated_stats_.freed; } -size_t AsanThreadRegistry::GetHeapSize() { +uptr AsanThreadRegistry::GetHeapSize() { ScopedLock lock(&mu_); UpdateAccumulatedStatsUnlocked(); return accumulated_stats_.mmaped; } -size_t AsanThreadRegistry::GetFreeBytes() { +uptr AsanThreadRegistry::GetFreeBytes() { ScopedLock lock(&mu_); UpdateAccumulatedStatsUnlocked(); return accumulated_stats_.mmaped @@ -185,18 +131,17 @@ size_t AsanThreadRegistry::GetFreeBytes() { + accumulated_stats_.really_freed_redzones; } -AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) { - CHECK(tid >= 0); +AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) { CHECK(tid < n_threads_); CHECK(thread_summaries_[tid]); return thread_summaries_[tid]; } -AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) { +AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) { ScopedLock lock(&mu_); - for (int tid = 0; tid < n_threads_; tid++) { + for (u32 tid = 0; tid < n_threads_; tid++) { AsanThread *t = thread_summaries_[tid]->thread(); - if (!t) continue; + if (!t || !(t->fake_stack().StackSize())) continue; if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { return t; } @@ -205,20 +150,20 @@ AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) { } void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { - for (int tid = 0; tid < n_threads_; tid++) { + for (u32 tid = 0; tid < n_threads_; tid++) { AsanThread *t = thread_summaries_[tid]->thread(); - if (t != NULL) { + if (t != 0) { FlushToAccumulatedStatsUnlocked(&t->stats()); } } } void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { - // AsanStats consists of variables of type size_t only. - size_t *dst = (size_t*)&accumulated_stats_; - size_t *src = (size_t*)stats; - size_t num_fields = sizeof(AsanStats) / sizeof(size_t); - for (size_t i = 0; i < num_fields; i++) { + // AsanStats consists of variables of type uptr only. + uptr *dst = (uptr*)&accumulated_stats_; + uptr *src = (uptr*)stats; + uptr num_fields = sizeof(AsanStats) / sizeof(uptr); + for (uptr i = 0; i < num_fields; i++) { dst[i] += src[i]; src[i] = 0; } |