[ASan] Switch ASan to generic ThreadRegistry from sanitizer_common. Delete ASan-specific AsanThreadRegistry.

llvm-svn: 177634
This commit is contained in:
Alexey Samsonov
2013-03-21 11:23:41 +00:00
parent 5700f40d80
commit 54afba8b62
19 changed files with 203 additions and 294 deletions

View File

@@ -20,7 +20,6 @@ set(ASAN_SOURCES
asan_stack.cc
asan_stats.cc
asan_thread.cc
asan_thread_registry.cc
asan_win.cc
)

View File

@@ -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"

View File

@@ -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"

View File

@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
namespace __asan {

View File

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

View File

@@ -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"

View File

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

View File

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

View File

@@ -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.

View File

@@ -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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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