summaryrefslogtreecommitdiff
path: root/lib/asan
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2013-03-21 11:23:41 +0000
committerAlexey Samsonov <samsonov@google.com>2013-03-21 11:23:41 +0000
commitdef1be9b7ef4091ce465c0fbfb26cdb52128ade8 (patch)
treeec6af26f13d371b58d1ecd9d552f111233972403 /lib/asan
parenta38e40fde45acccb124f7419ecbe21ef6cfd306b (diff)
downloadcompiler-rt-def1be9b7ef4091ce465c0fbfb26cdb52128ade8.tar.gz
[ASan] Switch ASan to generic ThreadRegistry from sanitizer_common. Delete ASan-specific AsanThreadRegistry.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@177634 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/asan')
-rw-r--r--lib/asan/CMakeLists.txt1
-rw-r--r--lib/asan/asan_allocator.cc1
-rw-r--r--lib/asan/asan_allocator2.cc1
-rw-r--r--lib/asan/asan_fake_stack.cc1
-rw-r--r--lib/asan/asan_interceptors.cc16
-rw-r--r--lib/asan/asan_linux.cc1
-rw-r--r--lib/asan/asan_mac.cc7
-rw-r--r--lib/asan/asan_malloc_linux.cc1
-rw-r--r--lib/asan/asan_malloc_mac.cc1
-rw-r--r--lib/asan/asan_posix.cc1
-rw-r--r--lib/asan/asan_report.cc64
-rw-r--r--lib/asan/asan_report.h2
-rw-r--r--lib/asan/asan_rtl.cc12
-rw-r--r--lib/asan/asan_stats.cc15
-rw-r--r--lib/asan/asan_stats.h2
-rw-r--r--lib/asan/asan_thread.cc142
-rw-r--r--lib/asan/asan_thread.h76
-rw-r--r--lib/asan/asan_thread_registry.cc96
-rw-r--r--lib/asan/asan_thread_registry.h57
19 files changed, 203 insertions, 294 deletions
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index 3e3505efc..bddae9fe3 100644
--- a/lib/asan/CMakeLists.txt
+++ b/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/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index 49c1f73ed..63454b78e 100644
--- a/lib/asan/asan_allocator.cc
+++ b/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/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc
index 63076c72d..bb3cf06af 100644
--- a/lib/asan/asan_allocator2.cc
+++ b/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/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index 9ba54c7b1..dd18ba7ff 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/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/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 353c94015..b84b9fd40 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/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/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 58b96a650..7c7ab1e90 100644
--- a/lib/asan/asan_linux.cc
+++ b/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/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index e88aa6a7d..eb1ca93ec 100644
--- a/lib/asan/asan_mac.cc
+++ b/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 <crt_externs.h> // 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/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 1a0b38990..f064651cc 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/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/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index eb66ddab0..de4000617 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/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/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 10b671bb4..6896c224b 100644
--- a/lib/asan/asan_posix.cc
+++ b/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/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index d2315dc24..c2c6d86bc 100644
--- a/lib/asan/asan_report.cc
+++ b/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/lib/asan/asan_report.h b/lib/asan/asan_report.h
index 55a8039dc..db271fc10 100644
--- a/lib/asan/asan_report.h
+++ b/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/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index bad564cac..308d4e309 100644
--- a/lib/asan/asan_rtl.cc
+++ b/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/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc
index b1fe7bc42..66e7663d9 100644
--- a/lib/asan/asan_stats.cc
+++ b/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<AsanThreadContext*>(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/lib/asan/asan_stats.h b/lib/asan/asan_stats.h
index 920ac0502..68495fb33 100644
--- a/lib/asan/asan_stats.h
+++ b/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/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 8f5a8df56..3bce19e4a 100644
--- a/lib/asan/asan_thread.cc
+++ b/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<CreateThreadContextArgs*>(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<AsanThreadContext *>(
+ 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<AsanThreadContext*>(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<AsanThreadContext *>(
+ asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
+ (void *)addr));
+ return tctx ? tctx->thread : 0;
+}
+
} // namespace __asan
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index bfdccfbd4..b141775fa 100644
--- a/lib/asan/asan_thread.h
+++ b/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/lib/asan/asan_thread_registry.cc b/lib/asan/asan_thread_registry.cc
deleted file mode 100644
index 82ee34dc3..000000000
--- a/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/lib/asan/asan_thread_registry.h b/lib/asan/asan_thread_registry.h
deleted file mode 100644
index cfa8b668b..000000000
--- a/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