[hwasan] add basic ThreadRegistry plumbing, also rename HwasanThread to Thread

llvm-svn: 341005
This commit is contained in:
Kostya Serebryany 2018-08-30 00:13:20 +00:00
parent bed556133d
commit d0cd2db23b
7 changed files with 107 additions and 40 deletions

View File

@ -36,17 +36,17 @@ using namespace __sanitizer;
namespace __hwasan { namespace __hwasan {
void EnterSymbolizer() { void EnterSymbolizer() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
CHECK(t); CHECK(t);
t->EnterSymbolizer(); t->EnterSymbolizer();
} }
void ExitSymbolizer() { void ExitSymbolizer() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
CHECK(t); CHECK(t);
t->LeaveSymbolizer(); t->LeaveSymbolizer();
} }
bool IsInSymbolizer() { bool IsInSymbolizer() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
return t && t->InSymbolizer(); return t && t->InSymbolizer();
} }
@ -132,7 +132,7 @@ static void InitializeFlags() {
void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp, void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
void *context, bool request_fast_unwind) { void *context, bool request_fast_unwind) {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) { if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace. // Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope; SymbolizerScope sym_scope;
@ -178,6 +178,7 @@ void __hwasan_init() {
if (hwasan_inited) return; if (hwasan_inited) return;
hwasan_init_is_running = 1; hwasan_init_is_running = 1;
SanitizerToolName = "HWAddressSanitizer"; SanitizerToolName = "HWAddressSanitizer";
GetThreadRegistry();
InitTlsSize(); InitTlsSize();
@ -208,7 +209,7 @@ void __hwasan_init() {
HwasanAllocatorInit(); HwasanAllocatorInit();
HwasanThread *main_thread = HwasanThread::Create(nullptr, nullptr); Thread *main_thread = Thread::Create(nullptr, nullptr);
SetCurrentThread(main_thread); SetCurrentThread(main_thread);
main_thread->Init(); main_thread->Init();
@ -428,7 +429,7 @@ void __hwasan_handle_longjmp(const void *sp_dst) {
static const u8 kFallbackTag = 0xBB; static const u8 kFallbackTag = 0xBB;
u8 __hwasan_generate_tag() { u8 __hwasan_generate_tag() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
if (!t) return kFallbackTag; if (!t) return kFallbackTag;
return t->GenerateRandomTag(); return t->GenerateRandomTag();
} }

View File

@ -136,7 +136,7 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
} }
ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack); ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);
} }
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
void *allocated; void *allocated;
if (t) { if (t) {
AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
@ -199,7 +199,7 @@ void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
meta->free_context_id = free_context_id; meta->free_context_id = free_context_id;
// This memory will not be reused by anyone else, so we are free to keep it // This memory will not be reused by anyone else, so we are free to keep it
// poisoned. // poisoned.
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
if (flags()->max_free_fill_size > 0) { if (flags()->max_free_fill_size > 0) {
uptr fill_size = Min(size, (uptr)flags()->max_free_fill_size); uptr fill_size = Min(size, (uptr)flags()->max_free_fill_size);
internal_memset(untagged_ptr, flags()->free_fill_byte, fill_size); internal_memset(untagged_ptr, flags()->free_fill_byte, fill_size);

View File

@ -50,18 +50,18 @@ DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
DECLARE_REAL(void *, memset, void *dest, int c, uptr n) DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
bool IsInInterceptorScope() { bool IsInInterceptorScope() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
return t && t->InInterceptorScope(); return t && t->InInterceptorScope();
} }
struct InterceptorScope { struct InterceptorScope {
InterceptorScope() { InterceptorScope() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
if (t) if (t)
t->EnterInterceptorScope(); t->EnterInterceptorScope();
} }
~InterceptorScope() { ~InterceptorScope() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
if (t) if (t)
t->LeaveInterceptorScope(); t->LeaveInterceptorScope();
} }
@ -294,7 +294,7 @@ extern "C" int pthread_attr_destroy(void *attr);
static void *HwasanThreadStartFunc(void *arg) { static void *HwasanThreadStartFunc(void *arg) {
__hwasan_thread_enter(); __hwasan_thread_enter();
return ((HwasanThread *)arg)->ThreadStart(); return ((Thread *)arg)->ThreadStart();
} }
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
@ -308,7 +308,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
AdjustStackSize(attr); AdjustStackSize(attr);
HwasanThread *t = HwasanThread::Create(callback, param); Thread *t = Thread::Create(callback, param);
int res = REAL(pthread_create)(th, attr, HwasanThreadStartFunc, t); int res = REAL(pthread_create)(th, attr, HwasanThreadStartFunc, t);

View File

@ -214,13 +214,13 @@ void InstallAtExitHandler() {
// ---------------------- TSD ---------------- {{{1 // ---------------------- TSD ---------------- {{{1
extern "C" void __hwasan_thread_enter() { extern "C" void __hwasan_thread_enter() {
HwasanThread *t = HwasanThread::Create(nullptr, nullptr); Thread *t = Thread::Create(nullptr, nullptr);
SetCurrentThread(t); SetCurrentThread(t);
t->Init(); t->Init();
} }
extern "C" void __hwasan_thread_exit() { extern "C" void __hwasan_thread_exit() {
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
// Make sure that signal handler can not see a stale current thread pointer. // Make sure that signal handler can not see a stale current thread pointer.
atomic_signal_fence(memory_order_seq_cst); atomic_signal_fence(memory_order_seq_cst);
if (t) if (t)
@ -232,7 +232,7 @@ static pthread_key_t tsd_key;
static bool tsd_key_inited = false; static bool tsd_key_inited = false;
void HwasanTSDDtor(void *tsd) { void HwasanTSDDtor(void *tsd) {
HwasanThread *t = (HwasanThread*)tsd; Thread *t = (Thread*)tsd;
if (t->destructor_iterations_ > 1) { if (t->destructor_iterations_ > 1) {
t->destructor_iterations_--; t->destructor_iterations_--;
CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
@ -247,24 +247,24 @@ void HwasanTSDInit() {
CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor)); CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor));
} }
HwasanThread *GetCurrentThread() { Thread *GetCurrentThread() {
return (HwasanThread *)pthread_getspecific(tsd_key); return (Thread *)pthread_getspecific(tsd_key);
} }
void SetCurrentThread(HwasanThread *t) { void SetCurrentThread(Thread *t) {
// Make sure that HwasanTSDDtor gets called at the end. // Make sure that HwasanTSDDtor gets called at the end.
CHECK(tsd_key_inited); CHECK(tsd_key_inited);
// Make sure we do not reset the current HwasanThread. // Make sure we do not reset the current Thread.
CHECK_EQ(0, pthread_getspecific(tsd_key)); CHECK_EQ(0, pthread_getspecific(tsd_key));
pthread_setspecific(tsd_key, (void *)t); pthread_setspecific(tsd_key, (void *)t);
} }
#elif SANITIZER_ANDROID #elif SANITIZER_ANDROID
void HwasanTSDInit() {} void HwasanTSDInit() {}
HwasanThread *GetCurrentThread() { Thread *GetCurrentThread() {
return (HwasanThread*)*get_android_tls_ptr(); return (Thread*)*get_android_tls_ptr();
} }
void SetCurrentThread(HwasanThread *t) { void SetCurrentThread(Thread *t) {
*get_android_tls_ptr() = (uptr)t; *get_android_tls_ptr() = (uptr)t;
} }
#else #else

View File

@ -206,10 +206,12 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
// * remove reduntant fields from the allocator metadata // * remove reduntant fields from the allocator metadata
// * use the allocations found in the ring buffer for the main report. // * use the allocations found in the ring buffer for the main report.
HeapAllocationRecord har; HeapAllocationRecord har;
HwasanThread *t = GetCurrentThread(); Thread *t = GetCurrentThread();
if (t && FindHeapAllocation(t->heap_allocations(), tagged_addr, &har)) if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har))
Printf("Address found in the ring buffer: %p %u %u\n", har.tagged_addr, Printf("Address found in the ring buffer: %p %u %u\n", har.tagged_addr,
har.free_context_id, har.requested_size); har.free_context_id, har.requested_size);
Printf("Current thread: tid: %d\n", t->context()->tid);
PrintTagsAroundAddr(tag_ptr); PrintTagsAroundAddr(tag_ptr);

View File

@ -6,6 +6,7 @@
#include "hwasan_interface_internal.h" #include "hwasan_interface_internal.h"
#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h" #include "sanitizer_common/sanitizer_tls_get_addr.h"
namespace __hwasan { namespace __hwasan {
@ -23,21 +24,24 @@ static u32 RandomSeed() {
return seed; return seed;
} }
HwasanThread *HwasanThread::Create(thread_callback_t start_routine, Thread *Thread::Create(thread_callback_t start_routine,
void *arg) { void *arg) {
uptr PageSize = GetPageSizeCached(); uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(HwasanThread), PageSize); uptr size = RoundUpTo(sizeof(Thread), PageSize);
HwasanThread *thread = (HwasanThread*)MmapOrDie(size, __func__); Thread *thread = (Thread*)MmapOrDie(size, __func__);
thread->start_routine_ = start_routine; thread->start_routine_ = start_routine;
thread->arg_ = arg; thread->arg_ = arg;
thread->destructor_iterations_ = GetPthreadDestructorIterations(); thread->destructor_iterations_ = GetPthreadDestructorIterations();
thread->random_state_ = flags()->random_tags ? RandomSeed() : 0; thread->random_state_ = flags()->random_tags ? RandomSeed() : 0;
thread->context_ = nullptr;
ThreadContext::Args args = {thread};
thread->tid_ = GetThreadRegistry().CreateThread(0, false, 0, &args);
if (auto sz = flags()->heap_history_size) if (auto sz = flags()->heap_history_size)
thread->heap_allocations_ = RingBuffer<HeapAllocationRecord>::New(sz); thread->heap_allocations_ = RingBuffer<HeapAllocationRecord>::New(sz);
return thread; return thread;
} }
void HwasanThread::SetThreadStackAndTls() { void Thread::SetThreadStackAndTls() {
// If this process is "init" (pid 1), /proc may not be mounted yet. // If this process is "init" (pid 1), /proc may not be mounted yet.
if (IsMainThread() && !FileExists("/proc/self/maps")) { if (IsMainThread() && !FileExists("/proc/self/maps")) {
stack_top_ = stack_bottom_ = 0; stack_top_ = stack_bottom_ = 0;
@ -58,7 +62,7 @@ void HwasanThread::SetThreadStackAndTls() {
CHECK(MemIsApp(stack_top_ - 1)); CHECK(MemIsApp(stack_top_ - 1));
} }
void HwasanThread::Init() { void Thread::Init() {
SetThreadStackAndTls(); SetThreadStackAndTls();
if (stack_bottom_) { if (stack_bottom_) {
CHECK(MemIsApp(stack_bottom_)); CHECK(MemIsApp(stack_bottom_));
@ -66,24 +70,24 @@ void HwasanThread::Init() {
} }
} }
void HwasanThread::ClearShadowForThreadStackAndTLS() { void Thread::ClearShadowForThreadStackAndTLS() {
if (stack_top_ != stack_bottom_) if (stack_top_ != stack_bottom_)
TagMemory(stack_bottom_, stack_top_ - stack_bottom_, 0); TagMemory(stack_bottom_, stack_top_ - stack_bottom_, 0);
if (tls_begin_ != tls_end_) if (tls_begin_ != tls_end_)
TagMemory(tls_begin_, tls_end_ - tls_begin_, 0); TagMemory(tls_begin_, tls_end_ - tls_begin_, 0);
} }
void HwasanThread::Destroy() { void Thread::Destroy() {
malloc_storage().CommitBack(); malloc_storage().CommitBack();
ClearShadowForThreadStackAndTLS(); ClearShadowForThreadStackAndTLS();
uptr size = RoundUpTo(sizeof(HwasanThread), GetPageSizeCached()); uptr size = RoundUpTo(sizeof(Thread), GetPageSizeCached());
if (heap_allocations_) if (heap_allocations_)
heap_allocations_->Delete(); heap_allocations_->Delete();
UnmapOrDie(this, size); UnmapOrDie(this, size);
DTLS_Destroy(); DTLS_Destroy();
} }
thread_return_t HwasanThread::ThreadStart() { thread_return_t Thread::ThreadStart() {
return start_routine_(arg_); return start_routine_(arg_);
} }
@ -95,7 +99,7 @@ static u32 xorshift(u32 state) {
} }
// Generate a (pseudo-)random non-zero tag. // Generate a (pseudo-)random non-zero tag.
tag_t HwasanThread::GenerateRandomTag() { tag_t Thread::GenerateRandomTag() {
tag_t tag; tag_t tag;
do { do {
if (flags()->random_tags) { if (flags()->random_tags) {
@ -111,4 +115,32 @@ tag_t HwasanThread::GenerateRandomTag() {
return tag; return tag;
} }
void ThreadContext::OnCreated(void *arg) {
Args *args = static_cast<Args*>(arg);
thread = args->thread;
thread->set_context(this);
}
void ThreadContext::OnFinished() {
thread = nullptr;
}
static const u32 kMaxLiveThreads = 1024;
static ThreadContextBase *ThreadContextFactory(u32 tid) {
static ALIGNED(16) char placeholder[sizeof(ThreadContext) * kMaxLiveThreads];
void *mem = &placeholder[0] + tid * sizeof(ThreadContext);
CHECK_LT(tid, kMaxLiveThreads);
return new (mem) ThreadContext(tid);
}
ThreadRegistry &GetThreadRegistry() {
static ALIGNED(16) char placeholder[sizeof(ThreadRegistry)];
static ThreadRegistry *registry;
if (!registry)
registry = new (placeholder)
ThreadRegistry(ThreadContextFactory, kMaxLiveThreads, kMaxLiveThreads);
return *registry;
}
} // namespace __hwasan } // namespace __hwasan

View File

@ -16,12 +16,33 @@
#include "hwasan_allocator.h" #include "hwasan_allocator.h"
#include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
namespace __hwasan { namespace __hwasan {
class HwasanThread { class Thread;
class ThreadContext : public ThreadContextBase {
public: public:
static HwasanThread *Create(thread_callback_t start_routine, void *arg); explicit ThreadContext(int tid)
: ThreadContextBase(tid), thread(nullptr){}
Thread *thread;
void OnCreated(void *arg) override;
void OnFinished() override;
struct Args {
Thread *thread;
};
};
// We want this to be small.
COMPILER_CHECK(sizeof(ThreadContext) <= 256);
class Thread {
public:
static Thread *Create(thread_callback_t start_routine, void *arg);
void Destroy(); void Destroy();
void Init(); void Init();
@ -54,12 +75,15 @@ class HwasanThread {
return heap_allocations_; return heap_allocations_;
} }
void set_context(ThreadContext *context) { context_ = context; }
const ThreadContext *context() const { return context_; }
tag_t GenerateRandomTag(); tag_t GenerateRandomTag();
int destructor_iterations_; int destructor_iterations_;
private: private:
// NOTE: There is no HwasanThread constructor. It is allocated // NOTE: There is no Thread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state. // via mmap() and *must* be valid in zero-initialized state.
void SetThreadStackAndTls(); void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS(); void ClearShadowForThreadStackAndTLS();
@ -79,10 +103,18 @@ class HwasanThread {
HwasanThreadLocalMallocStorage malloc_storage_; HwasanThreadLocalMallocStorage malloc_storage_;
HeapAllocationsRingBuffer *heap_allocations_; HeapAllocationsRingBuffer *heap_allocations_;
u32 tid_;
ThreadContext *context_;
}; };
HwasanThread *GetCurrentThread(); Thread *GetCurrentThread();
void SetCurrentThread(HwasanThread *t); void SetCurrentThread(Thread *t);
// Returns the ThreadRegistry singleton.
ThreadRegistry &GetThreadRegistry();
// Returns the ThreadRegistry singleton.
} // namespace __hwasan } // namespace __hwasan