From: Alexey Samsonov Date: Thu, 21 Mar 2013 11:23:41 +0000 (+0000) Subject: [ASan] Switch ASan to generic ThreadRegistry from sanitizer_common. Delete ASan-speci... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=54afba8b6255e07f6099ca66dd0dfd1be033ea41;p=platform%2Fupstream%2Fllvm.git [ASan] Switch ASan to generic ThreadRegistry from sanitizer_common. Delete ASan-specific AsanThreadRegistry. llvm-svn: 177634 --- diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 3e3505e..bddae9f 100644 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -20,7 +20,6 @@ set(ASAN_SOURCES asan_stack.cc asan_stats.cc asan_thread.cc - asan_thread_registry.cc asan_win.cc ) diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc index 49c1f73..63454b7 100644 --- a/compiler-rt/lib/asan/asan_allocator.cc +++ b/compiler-rt/lib/asan/asan_allocator.cc @@ -33,7 +33,6 @@ #include "asan_stats.h" #include "asan_report.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_mutex.h" diff --git a/compiler-rt/lib/asan/asan_allocator2.cc b/compiler-rt/lib/asan/asan_allocator2.cc index 63076c7..bb3cf06 100644 --- a/compiler-rt/lib/asan/asan_allocator2.cc +++ b/compiler-rt/lib/asan/asan_allocator2.cc @@ -21,7 +21,6 @@ #include "asan_mapping.h" #include "asan_report.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_list.h" diff --git a/compiler-rt/lib/asan/asan_fake_stack.cc b/compiler-rt/lib/asan/asan_fake_stack.cc index 9ba54c7..dd18ba7 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cc +++ b/compiler-rt/lib/asan/asan_fake_stack.cc @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_thread.h" -#include "asan_thread_registry.h" namespace __asan { diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 353c940..b84b9fd 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -20,7 +20,6 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" -#include "asan_thread_registry.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_libc.h" @@ -91,7 +90,7 @@ static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { void SetThreadName(const char *name) { AsanThread *t = GetCurrentThread(); if (t) - t->summary()->set_name(name); + asanThreadRegistry().SetThreadName(t->tid(), name); } } // namespace __asan @@ -116,16 +115,23 @@ using namespace __asan; // NOLINT static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { AsanThread *t = (AsanThread*)arg; SetCurrentThread(t); - return t->ThreadStart(); + return t->ThreadStart(GetTid()); } #if ASAN_INTERCEPT_PTHREAD_CREATE +extern "C" int pthread_attr_getdetachstate(void *attr, int *v); + INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { GET_STACK_TRACE_THREAD; + int detached = 0; + if (attr != 0) + pthread_attr_getdetachstate(attr, &detached); + u32 current_tid = GetCurrentTidOrInvalid(); - AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack); - asanThreadRegistry().RegisterThread(t); + AsanThread *t = AsanThread::Create(start_routine, arg); + CreateThreadContextArgs args = { t, &stack }; + asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args); return REAL(pthread_create)(thread, attr, asan_thread_start, t); } #endif // ASAN_INTERCEPT_PTHREAD_CREATE diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index 58b96a6..7c7ab1e 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -18,7 +18,6 @@ #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index e88aa6a..eb1ca93 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -21,7 +21,6 @@ #include "asan_mapping.h" #include "asan_stack.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_libc.h" #include // for _NSGetArgv @@ -293,9 +292,11 @@ static ALWAYS_INLINE void asan_register_worker_thread(int parent_tid, StackTrace *stack) { AsanThread *t = GetCurrentThread(); if (!t) { - t = AsanThread::Create(parent_tid, 0, 0, stack); - asanThreadRegistry().RegisterThread(t); + t = AsanThread::Create(0, 0); + CreateThreadContextArgs args = { t, stack }; + asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args); t->Init(); + asanThreadRegistry().StartThread(t->tid(), 0, 0); SetCurrentThread(t); } } diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cc b/compiler-rt/lib/asan/asan_malloc_linux.cc index 1a0b389..f064651 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cc +++ b/compiler-rt/lib/asan/asan_malloc_linux.cc @@ -21,7 +21,6 @@ #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_stack.h" -#include "asan_thread_registry.h" #if SANITIZER_ANDROID DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size) diff --git a/compiler-rt/lib/asan/asan_malloc_mac.cc b/compiler-rt/lib/asan/asan_malloc_mac.cc index eb66dda..de40006 100644 --- a/compiler-rt/lib/asan/asan_malloc_mac.cc +++ b/compiler-rt/lib/asan/asan_malloc_mac.cc @@ -27,7 +27,6 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" -#include "asan_thread_registry.h" // Similar code is used in Google Perftools, // http://code.google.com/p/google-perftools. diff --git a/compiler-rt/lib/asan/asan_posix.cc b/compiler-rt/lib/asan/asan_posix.cc index 10b671b..6896c22 100644 --- a/compiler-rt/lib/asan/asan_posix.cc +++ b/compiler-rt/lib/asan/asan_posix.cc @@ -20,7 +20,6 @@ #include "asan_mapping.h" #include "asan_report.h" #include "asan_stack.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index d2315dc..c2c6d86 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -17,7 +17,6 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_symbolizer.h" @@ -237,7 +236,7 @@ bool DescribeAddressIfShadow(uptr addr) { } bool DescribeAddressIfStack(uptr addr, uptr access_size) { - AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr); + AsanThread *t = FindThreadByStackAddress(addr); if (!t) return false; const sptr kBufSize = 4095; char buf[kBufSize]; @@ -286,7 +285,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { Printf("HINT: this may be a false positive if your program uses " "some custom stack unwind mechanism or swapcontext\n" " (longjmp and C++ exceptions *are* supported)\n"); - DescribeThread(t->summary()); + DescribeThread(t->context()); return true; } @@ -315,10 +314,10 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr, } // Return " (thread_name) " or an empty string if the name is empty. -const char *ThreadNameWithParenthesis(AsanThreadSummary *t, char buff[], +const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], uptr buff_len) { - const char *name = t->name(); - if (*name == 0) return ""; + const char *name = t->name; + if (name[0] == '\0') return ""; buff[0] = 0; internal_strncat(buff, " (", 3); internal_strncat(buff, name, buff_len - 4); @@ -329,7 +328,8 @@ const char *ThreadNameWithParenthesis(AsanThreadSummary *t, char buff[], const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) { if (tid == kInvalidTid) return ""; - AsanThreadSummary *t = asanThreadRegistry().FindByTid(tid); + asanThreadRegistry().CheckLocked(); + AsanThreadContext *t = GetThreadContextByTidLocked(tid); return ThreadNameWithParenthesis(t, buff, buff_len); } @@ -338,8 +338,9 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { if (!chunk.IsValid()) return; DescribeAccessToHeapChunk(chunk, addr, access_size); CHECK(chunk.AllocTid() != kInvalidTid); - AsanThreadSummary *alloc_thread = - asanThreadRegistry().FindByTid(chunk.AllocTid()); + asanThreadRegistry().CheckLocked(); + AsanThreadContext *alloc_thread = + GetThreadContextByTidLocked(chunk.AllocTid()); StackTrace alloc_stack; chunk.GetAllocStack(&alloc_stack); AsanThread *t = GetCurrentThread(); @@ -347,30 +348,30 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { char tname[128]; Decorator d; if (chunk.FreeTid() != kInvalidTid) { - AsanThreadSummary *free_thread = - asanThreadRegistry().FindByTid(chunk.FreeTid()); + AsanThreadContext *free_thread = + GetThreadContextByTidLocked(chunk.FreeTid()); Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), - free_thread->tid(), + free_thread->tid, ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), d.EndAllocation()); StackTrace free_stack; chunk.GetFreeStack(&free_stack); PrintStack(&free_stack); Printf("%spreviously allocated by thread T%d%s here:%s\n", - d.Allocation(), alloc_thread->tid(), + d.Allocation(), alloc_thread->tid, ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), d.EndAllocation()); PrintStack(&alloc_stack); - DescribeThread(t->summary()); + DescribeThread(t->context()); DescribeThread(free_thread); DescribeThread(alloc_thread); } else { Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), - alloc_thread->tid(), + alloc_thread->tid, ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), d.EndAllocation()); PrintStack(&alloc_stack); - DescribeThread(t->summary()); + DescribeThread(t->context()); DescribeThread(alloc_thread); } } @@ -390,26 +391,27 @@ void DescribeAddress(uptr addr, uptr access_size) { // ------------------- Thread description -------------------- {{{1 -void DescribeThread(AsanThreadSummary *summary) { - CHECK(summary); +void DescribeThread(AsanThreadContext *context) { + CHECK(context); + asanThreadRegistry().CheckLocked(); // No need to announce the main thread. - if (summary->tid() == 0 || summary->announced()) { + if (context->tid == 0 || context->announced) { return; } - summary->set_announced(true); + context->announced = true; char tname[128]; - Printf("Thread T%d%s", summary->tid(), - ThreadNameWithParenthesis(summary->tid(), tname, sizeof(tname))); + Printf("Thread T%d%s", context->tid, + ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); Printf(" created by T%d%s here:\n", - summary->parent_tid(), - ThreadNameWithParenthesis(summary->parent_tid(), + context->parent_tid, + ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); - PrintStack(summary->stack()); + PrintStack(&context->stack); // Recursively described parent thread if needed. if (flags()->print_full_thread_history) { - AsanThreadSummary *parent_summary = - asanThreadRegistry().FindByTid(summary->parent_tid()); - DescribeThread(parent_summary); + AsanThreadContext *parent_context = + GetThreadContextByTidLocked(context->parent_tid); + DescribeThread(parent_context); } } @@ -440,6 +442,10 @@ class ScopedInErrorReport { internal__exit(flags()->exitcode); } ASAN_ON_ERROR(); + // Make sure the registry is locked while we're printing an error report. + // We can lock the registry only here to avoid self-deadlock in case of + // recursive reports. + asanThreadRegistry().Lock(); reporting_thread_tid = GetCurrentTidOrInvalid(); Printf("====================================================" "=============\n"); @@ -456,7 +462,7 @@ class ScopedInErrorReport { // Make sure the current thread is announced. AsanThread *curr_thread = GetCurrentThread(); if (curr_thread) { - DescribeThread(curr_thread->summary()); + DescribeThread(curr_thread->context()); } // Print memory stats. if (flags()->print_stats) diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h index 55a8039..db271fc 100644 --- a/compiler-rt/lib/asan/asan_report.h +++ b/compiler-rt/lib/asan/asan_report.h @@ -29,7 +29,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size); // Determines memory type on its own. void DescribeAddress(uptr addr, uptr access_size); -void DescribeThread(AsanThreadSummary *summary); +void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr); diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index bad564ca..308d4e3 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -19,7 +19,6 @@ #include "asan_stack.h" #include "asan_stats.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" @@ -517,8 +516,15 @@ void __asan_init() { asan_inited = 1; asan_init_is_running = false; - asanThreadRegistry().Init(); - asanThreadRegistry().GetMain()->ThreadStart(); + // Create main thread. + AsanTSDInit(AsanThread::TSDDtor); + AsanThread *main_thread = AsanThread::Create(0, 0); + CreateThreadContextArgs create_main_args = { main_thread, 0 }; + u32 main_tid = asanThreadRegistry().CreateThread( + 0, true, 0, &create_main_args); + CHECK_EQ(0, main_tid); + SetCurrentThread(main_thread); + main_thread->ThreadStart(GetPid()); force_interface_symbols(); // no-op. InitializeAllocator(); diff --git a/compiler-rt/lib/asan/asan_stats.cc b/compiler-rt/lib/asan/asan_stats.cc index b1fe7bc..66e7663 100644 --- a/compiler-rt/lib/asan/asan_stats.cc +++ b/compiler-rt/lib/asan/asan_stats.cc @@ -14,7 +14,7 @@ #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_stats.h" -#include "asan_thread_registry.h" +#include "asan_thread.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_stackdepot.h" @@ -75,7 +75,7 @@ static AsanStats accumulated_stats(LINKER_INITIALIZED); static uptr max_malloced_memory; static BlockingMutex acc_stats_lock(LINKER_INITIALIZED); -void FlushToAccumulatedStatsUnlocked(AsanStats *stats) { +static void FlushToAccumulatedStatsUnlocked(AsanStats *stats) { acc_stats_lock.CheckLocked(); uptr *dst = (uptr*)&accumulated_stats; uptr *src = (uptr*)stats; @@ -86,9 +86,18 @@ void FlushToAccumulatedStatsUnlocked(AsanStats *stats) { } } +static void FlushThreadStats(ThreadContextBase *tctx_base, void *arg) { + AsanThreadContext *tctx = static_cast(tctx_base); + if (AsanThread *t = tctx->thread) + FlushToAccumulatedStatsUnlocked(&t->stats()); +} + static void UpdateAccumulatedStatsUnlocked() { acc_stats_lock.CheckLocked(); - asanThreadRegistry().FlushAllStats(); + { + ThreadRegistryLock l(&asanThreadRegistry()); + asanThreadRegistry().RunCallbackForEachThreadLocked(FlushThreadStats, 0); + } FlushToAccumulatedStatsUnlocked(&unknown_thread_stats); // This is not very accurate: we may miss allocation peaks that happen // between two updates of accumulated_stats_. For more accurate bookkeeping diff --git a/compiler-rt/lib/asan/asan_stats.h b/compiler-rt/lib/asan/asan_stats.h index 920ac05..68495fb 100644 --- a/compiler-rt/lib/asan/asan_stats.h +++ b/compiler-rt/lib/asan/asan_stats.h @@ -64,8 +64,6 @@ AsanStats &GetCurrentThreadStats(); void GetAccumulatedStats(AsanStats *stats); // Flushes a given stats into accumulated stats. void FlushToAccumulatedStats(AsanStats *stats); -// FIXME: Hide this method when AsanThreadRegistry is removed. -void FlushToAccumulatedStatsUnlocked(AsanStats *stats); // A cross-platform equivalent of malloc_statistics_t on Mac OS. struct AsanMallocStats { diff --git a/compiler-rt/lib/asan/asan_thread.cc b/compiler-rt/lib/asan/asan_thread.cc index 8f5a8df..3bce19e 100644 --- a/compiler-rt/lib/asan/asan_thread.cc +++ b/compiler-rt/lib/asan/asan_thread.cc @@ -15,44 +15,77 @@ #include "asan_interceptors.h" #include "asan_stack.h" #include "asan_thread.h" -#include "asan_thread_registry.h" #include "asan_mapping.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_placement_new.h" namespace __asan { -AsanThread::AsanThread(LinkerInitialized x) - : fake_stack_(x), - malloc_storage_(x), - stats_(x) { } +// AsanThreadContext implementation. -AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine, - void *arg, StackTrace *stack) { +void AsanThreadContext::OnCreated(void *arg) { + CreateThreadContextArgs *args = static_cast(arg); + if (args->stack) { + internal_memcpy(&stack, args->stack, sizeof(stack)); + } + thread = args->thread; + thread->set_context(this); +} + +void AsanThreadContext::OnFinished() { + // Drop the link to the AsanThread object. + thread = 0; +} + +static char thread_registry_placeholder[sizeof(ThreadRegistry)]; +static ThreadRegistry *asan_thread_registry; + +static ThreadContextBase *GetAsanThreadContext(u32 tid) { + void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext"); + return new(mem) AsanThreadContext(tid); +} + +ThreadRegistry &asanThreadRegistry() { + static bool initialized; + // Don't worry about thread_safety - this should be called when there is + // a single thread. + if (!initialized) { + // Never reuse ASan threads: we store pointer to AsanThreadContext + // in TSD and can't reliably tell when no more TSD destructors will + // be called. It would be wrong to reuse AsanThreadContext for another + // thread before all TSD destructors will be called for it. + asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry( + GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads); + initialized = true; + } + return *asan_thread_registry; +} + +AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { + return static_cast( + asanThreadRegistry().GetThreadLocked(tid)); +} + +// AsanThread implementation. + +AsanThread *AsanThread::Create(thread_callback_t start_routine, + void *arg) { uptr PageSize = GetPageSizeCached(); uptr size = RoundUpTo(sizeof(AsanThread), PageSize); AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__); thread->start_routine_ = start_routine; thread->arg_ = arg; - - const uptr kSummaryAllocSize = PageSize; - CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize); - AsanThreadSummary *summary = - (AsanThreadSummary*)MmapOrDie(PageSize, "AsanThreadSummary"); - summary->Init(parent_tid, stack); - summary->set_thread(thread); - thread->set_summary(summary); + thread->context_ = 0; return thread; } -void AsanThreadSummary::TSDDtor(void *tsd) { - AsanThreadSummary *summary = (AsanThreadSummary*)tsd; - if (flags()->verbosity >= 1) { - Report("T%d TSDDtor\n", summary->tid()); - } - if (summary->thread()) { - summary->thread()->Destroy(); - } +void AsanThread::TSDDtor(void *tsd) { + AsanThreadContext *context = (AsanThreadContext*)tsd; + if (flags()->verbosity >= 1) + Report("T%d TSDDtor\n", context->tid); + if (context->thread) + context->thread->Destroy(); } void AsanThread::Destroy() { @@ -60,8 +93,8 @@ void AsanThread::Destroy() { Report("T%d exited\n", tid()); } - asanThreadRegistry().UnregisterThread(this); - CHECK(summary()->thread() == 0); + asanThreadRegistry().FinishThread(tid()); + FlushToAccumulatedStats(&stats_); // 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. @@ -86,8 +119,9 @@ void AsanThread::Init() { AsanPlatformThreadInit(); } -thread_return_t AsanThread::ThreadStart() { +thread_return_t AsanThread::ThreadStart(uptr os_id) { Init(); + asanThreadRegistry().StartThread(tid(), os_id, 0); if (flags()->use_sigaltstack) SetAlternateSignalStack(); if (!start_routine_) { @@ -152,37 +186,45 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) { return (const char*)ptr[1]; } +static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, + void *addr) { + AsanThreadContext *tctx = static_cast(tctx_base); + AsanThread *t = tctx->thread; + return (t && t->fake_stack().StackSize() && + (t->fake_stack().AddrIsInFakeStack((uptr)addr) || + t->AddrIsInStack((uptr)addr))); +} + AsanThread *GetCurrentThread() { - AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); - if (!summary) { -#if SANITIZER_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 = - asanThreadRegistry().FindThreadByStackAddress((uptr)&summary); - if (thread && thread->tid() == 0) { - SetCurrentThread(thread); - return thread; + AsanThreadContext *context = (AsanThreadContext*)AsanTSDGet(); + if (!context) { + if (SANITIZER_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. + AsanThreadContext *tctx = GetThreadContextByTidLocked(0); + if (ThreadStackContainsAddress(tctx, &context)) { + SetCurrentThread(tctx->thread); + return tctx->thread; + } } -#endif return 0; } - return summary->thread(); + return context->thread; } void SetCurrentThread(AsanThread *t) { - CHECK(t->summary()); + CHECK(t->context()); if (flags()->verbosity >= 2) { Report("SetCurrentThread: %p for thread %p\n", - t->summary(), (void*)GetThreadSelf()); + t->context(), (void*)GetThreadSelf()); } // Make sure we do not reset the current AsanThread. - CHECK(AsanTSDGet() == 0); - AsanTSDSet(t->summary()); - CHECK(AsanTSDGet() == t->summary()); + CHECK_EQ(0, AsanTSDGet()); + AsanTSDSet(t->context()); + CHECK_EQ(t->context(), AsanTSDGet()); } u32 GetCurrentTidOrInvalid() { @@ -190,4 +232,12 @@ u32 GetCurrentTidOrInvalid() { return t ? t->tid() : kInvalidTid; } +AsanThread *FindThreadByStackAddress(uptr addr) { + asanThreadRegistry().CheckLocked(); + AsanThreadContext *tctx = static_cast( + asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, + (void *)addr)); + return tctx ? tctx->thread : 0; +} + } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index bfdccfb..b141775 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -19,71 +19,52 @@ #include "asan_stack.h" #include "asan_stats.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_thread_registry.h" namespace __asan { const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits. +const u32 kMaxNumberOfThreads = (1 << 22); // 4M class AsanThread; // These objects are created for every thread and are never deleted, // so we can find them by tid even if the thread is long dead. -class AsanThreadSummary { +class AsanThreadContext : public ThreadContextBase { public: - explicit AsanThreadSummary(LinkerInitialized) { } // for T0. - void Init(u32 parent_tid, StackTrace *stack) { - parent_tid_ = parent_tid; - announced_ = false; - tid_ = kInvalidTid; - if (stack) { - internal_memcpy(&stack_, stack, sizeof(*stack)); - } - thread_ = 0; - name_[0] = 0; + explicit AsanThreadContext(int tid) + : ThreadContextBase(tid), + announced(false), + thread(0) { + internal_memset(&stack, 0, sizeof(stack)); } - u32 tid() { return tid_; } - void set_tid(u32 tid) { tid_ = tid; } - u32 parent_tid() { return parent_tid_; } - bool announced() { return announced_; } - void set_announced(bool announced) { announced_ = announced; } - StackTrace *stack() { return &stack_; } - AsanThread *thread() { return thread_; } - void set_thread(AsanThread *thread) { thread_ = thread; } - static void TSDDtor(void *tsd); - void set_name(const char *name) { - internal_strncpy(name_, name, sizeof(name_) - 1); - } - const char *name() { return name_; } + bool announced; + StackTrace stack; + AsanThread *thread; - private: - u32 tid_; - u32 parent_tid_; - bool announced_; - StackTrace stack_; - AsanThread *thread_; - char name_[128]; + void OnCreated(void *arg); + void OnFinished(); }; -// AsanThreadSummary objects are never freed, so we need many of them. -COMPILER_CHECK(sizeof(AsanThreadSummary) <= 4094); +// AsanThreadContext objects are never freed, so we need many of them. +COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096); // AsanThread are stored in TSD and destroyed when the thread dies. class AsanThread { public: - explicit AsanThread(LinkerInitialized); // for T0. - static AsanThread *Create(u32 parent_tid, thread_callback_t start_routine, - void *arg, StackTrace *stack); + static AsanThread *Create(thread_callback_t start_routine, void *arg); + static void TSDDtor(void *tsd); void Destroy(); void Init(); // Should be called from the thread itself. - thread_return_t ThreadStart(); + thread_return_t ThreadStart(uptr os_id); uptr stack_top() { return stack_top_; } uptr stack_bottom() { return stack_bottom_; } uptr stack_size() { return stack_top_ - stack_bottom_; } - u32 tid() { return summary_->tid(); } - AsanThreadSummary *summary() { return summary_; } - void set_summary(AsanThreadSummary *summary) { summary_ = summary; } + u32 tid() { return context_->tid; } + AsanThreadContext *context() { return context_; } + void set_context(AsanThreadContext *context) { context_ = context; } const char *GetFrameNameByAddr(uptr addr, uptr *offset); @@ -96,9 +77,10 @@ class AsanThread { AsanStats &stats() { return stats_; } private: + AsanThread() {} void SetThreadStackTopAndBottom(); void ClearShadowForThreadStack(); - AsanThreadSummary *summary_; + AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; uptr stack_top_; @@ -109,10 +91,22 @@ class AsanThread { AsanStats stats_; }; +struct CreateThreadContextArgs { + AsanThread *thread; + StackTrace *stack; +}; + +// Returns a single instance of registry. +ThreadRegistry &asanThreadRegistry(); + +// Must be called under ThreadRegistryLock. +AsanThreadContext *GetThreadContextByTidLocked(u32 tid); + // Get the current thread. May return 0. AsanThread *GetCurrentThread(); void SetCurrentThread(AsanThread *t); u32 GetCurrentTidOrInvalid(); +AsanThread *FindThreadByStackAddress(uptr addr); } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_thread_registry.cc b/compiler-rt/lib/asan/asan_thread_registry.cc deleted file mode 100644 index 82ee34d..0000000 --- a/compiler-rt/lib/asan/asan_thread_registry.cc +++ /dev/null @@ -1,96 +0,0 @@ -//===-- asan_thread_registry.cc -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -// AsanThreadRegistry-related code. AsanThreadRegistry is a container -// for summaries of all created threads. -//===----------------------------------------------------------------------===// - -#include "asan_stack.h" -#include "asan_thread.h" -#include "asan_thread_registry.h" -#include "sanitizer_common/sanitizer_common.h" - -namespace __asan { - -static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED); - -AsanThreadRegistry &asanThreadRegistry() { - return asan_thread_registry; -} - -AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) - : main_thread_(x), - main_thread_summary_(x), - mu_(x) { } - -void AsanThreadRegistry::Init() { - AsanTSDInit(AsanThreadSummary::TSDDtor); - main_thread_.set_summary(&main_thread_summary_); - main_thread_summary_.set_thread(&main_thread_); - RegisterThread(&main_thread_); - SetCurrentThread(&main_thread_); - // At this point only one thread exists. - inited_ = true; -} - -void AsanThreadRegistry::RegisterThread(AsanThread *thread) { - BlockingMutexLock lock(&mu_); - u32 tid = n_threads_; - n_threads_++; - CHECK(n_threads_ < kMaxNumberOfThreads); - - AsanThreadSummary *summary = thread->summary(); - CHECK(summary != 0); - summary->set_tid(tid); - thread_summaries_[tid] = summary; -} - -void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { - BlockingMutexLock lock(&mu_); - FlushToAccumulatedStats(&thread->stats()); - AsanThreadSummary *summary = thread->summary(); - CHECK(summary); - summary->set_thread(0); -} - -AsanThread *AsanThreadRegistry::GetMain() { - return &main_thread_; -} - -void AsanThreadRegistry::FlushAllStats() { - BlockingMutexLock lock(&mu_); - for (u32 tid = 0; tid < n_threads_; tid++) { - AsanThread *t = thread_summaries_[tid]->thread(); - if (t != 0) { - FlushToAccumulatedStatsUnlocked(&t->stats()); - } - } -} - -AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) { - CHECK(tid < n_threads_); - CHECK(thread_summaries_[tid]); - return thread_summaries_[tid]; -} - -AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) { - BlockingMutexLock lock(&mu_); - for (u32 tid = 0; tid < n_threads_; tid++) { - AsanThread *t = thread_summaries_[tid]->thread(); - if (!t || !(t->fake_stack().StackSize())) continue; - if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { - return t; - } - } - return 0; -} - -} // namespace __asan diff --git a/compiler-rt/lib/asan/asan_thread_registry.h b/compiler-rt/lib/asan/asan_thread_registry.h deleted file mode 100644 index cfa8b66..0000000 --- a/compiler-rt/lib/asan/asan_thread_registry.h +++ /dev/null @@ -1,57 +0,0 @@ -//===-- asan_thread_registry.h ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -// ASan-private header for asan_thread_registry.cc -//===----------------------------------------------------------------------===// - -#ifndef ASAN_THREAD_REGISTRY_H -#define ASAN_THREAD_REGISTRY_H - -#include "asan_stack.h" -#include "asan_stats.h" -#include "asan_thread.h" -#include "sanitizer_common/sanitizer_mutex.h" - -namespace __asan { - -// Stores summaries of all created threads, returns current thread, -// thread by tid, thread by stack address. There is a single instance -// of AsanThreadRegistry for the whole program. -// AsanThreadRegistry is thread-safe. -class AsanThreadRegistry { - public: - explicit AsanThreadRegistry(LinkerInitialized); - void Init(); - void RegisterThread(AsanThread *thread); - void UnregisterThread(AsanThread *thread); - - AsanThread *GetMain(); - void FlushAllStats(); - - AsanThreadSummary *FindByTid(u32 tid); - AsanThread *FindThreadByStackAddress(uptr addr); - - private: - static const u32 kMaxNumberOfThreads = (1 << 22); // 4M - AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads]; - AsanThread main_thread_; - AsanThreadSummary main_thread_summary_; - u32 n_threads_; - BlockingMutex mu_; - bool inited_; -}; - -// Returns a single instance of registry. -AsanThreadRegistry &asanThreadRegistry(); - -} // namespace __asan - -#endif // ASAN_THREAD_REGISTRY_H