[hwasan] simplify the thread hangling: instead of the ThreadRegistry (too heavy) simply maintain a linked list of Threads
llvm-svn: 341111
This commit is contained in:
parent
0b2a541b90
commit
c359d9b8fa
|
@ -183,7 +183,6 @@ void __hwasan_init() {
|
|||
if (hwasan_inited) return;
|
||||
hwasan_init_is_running = 1;
|
||||
SanitizerToolName = "HWAddressSanitizer";
|
||||
GetThreadRegistry();
|
||||
|
||||
InitTlsSize();
|
||||
|
||||
|
|
|
@ -292,29 +292,28 @@ INTERCEPTOR(void *, malloc, SIZE_T size) {
|
|||
extern "C" int pthread_attr_init(void *attr);
|
||||
extern "C" int pthread_attr_destroy(void *attr);
|
||||
|
||||
struct ThreadStartArg {
|
||||
thread_callback_t callback;
|
||||
void *param;
|
||||
// TODO: something crazy is going on with pthread_create overwriting parts
|
||||
// of the stack, hense the padding.
|
||||
char padding[1000];
|
||||
};
|
||||
|
||||
static void *HwasanThreadStartFunc(void *arg) {
|
||||
__hwasan_thread_enter();
|
||||
return ((Thread *)arg)->ThreadStart();
|
||||
ThreadStartArg *A = reinterpret_cast<ThreadStartArg*>(arg);
|
||||
return A->callback(A->param);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
|
||||
void * param) {
|
||||
ENSURE_HWASAN_INITED(); // for GetTlsSize()
|
||||
__sanitizer_pthread_attr_t myattr;
|
||||
ScopedTaggingDisabler disabler;
|
||||
if (!attr) {
|
||||
pthread_attr_init(&myattr);
|
||||
attr = &myattr;
|
||||
}
|
||||
|
||||
AdjustStackSize(attr);
|
||||
|
||||
Thread *t = Thread::Create(callback, param);
|
||||
ThreadStartArg A;
|
||||
A.callback = callback;
|
||||
A.param = param;
|
||||
int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
|
||||
HwasanThreadStartFunc, UntagPtr(t));
|
||||
|
||||
if (attr == &myattr)
|
||||
pthread_attr_destroy(&myattr);
|
||||
&HwasanThreadStartFunc, &A);
|
||||
return res;
|
||||
}
|
||||
#endif // HWASAN_WITH_INTERCEPTORS
|
||||
|
|
|
@ -238,6 +238,7 @@ void HwasanTSDDtor(void *tsd) {
|
|||
CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
|
||||
return;
|
||||
}
|
||||
t->Destroy();
|
||||
__hwasan_thread_exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
|
|||
if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har))
|
||||
Printf("Address found in the ring buffer: %p %u %u\n", har.tagged_addr,
|
||||
har.free_context_id, har.requested_size);
|
||||
Printf("Current thread: tid: %d\n", t->context()->tid);
|
||||
|
||||
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
|
|
@ -24,6 +24,39 @@ static u32 RandomSeed() {
|
|||
return seed;
|
||||
}
|
||||
|
||||
static Thread *main_thread;
|
||||
static SpinMutex thread_list_mutex;
|
||||
|
||||
void Thread::InsertIntoThreadList(Thread *t) {
|
||||
CHECK(!t->next_);
|
||||
if (!main_thread) {
|
||||
main_thread = t;
|
||||
return;
|
||||
}
|
||||
SpinMutexLock l(&thread_list_mutex);
|
||||
Thread *last = main_thread;
|
||||
while (last->next_)
|
||||
last = last->next_;
|
||||
last->next_ = t;
|
||||
}
|
||||
|
||||
void Thread::RemoveFromThreadList(Thread *t) {
|
||||
CHECK_NE(t, main_thread);
|
||||
SpinMutexLock l(&thread_list_mutex);
|
||||
Thread *prev = main_thread;
|
||||
Thread *cur = prev->next_;
|
||||
CHECK(cur);
|
||||
while (cur) {
|
||||
if (cur == t) {
|
||||
prev->next_ = cur->next_;
|
||||
return;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next_;
|
||||
}
|
||||
CHECK(0 && "RemoveFromThreadList: thread not found");
|
||||
}
|
||||
|
||||
Thread *Thread::Create(thread_callback_t start_routine,
|
||||
void *arg) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
|
@ -33,11 +66,9 @@ Thread *Thread::Create(thread_callback_t start_routine,
|
|||
thread->arg_ = arg;
|
||||
thread->destructor_iterations_ = GetPthreadDestructorIterations();
|
||||
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)
|
||||
thread->heap_allocations_ = RingBuffer<HeapAllocationRecord>::New(sz);
|
||||
InsertIntoThreadList(thread);
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
@ -80,6 +111,7 @@ void Thread::ClearShadowForThreadStackAndTLS() {
|
|||
void Thread::Destroy() {
|
||||
malloc_storage().CommitBack();
|
||||
ClearShadowForThreadStackAndTLS();
|
||||
RemoveFromThreadList(this);
|
||||
uptr size = RoundUpTo(sizeof(Thread), GetPageSizeCached());
|
||||
if (heap_allocations_)
|
||||
heap_allocations_->Delete();
|
||||
|
@ -87,10 +119,6 @@ void Thread::Destroy() {
|
|||
DTLS_Destroy();
|
||||
}
|
||||
|
||||
thread_return_t Thread::ThreadStart() {
|
||||
return start_routine_(arg_);
|
||||
}
|
||||
|
||||
static u32 xorshift(u32 state) {
|
||||
state ^= state << 13;
|
||||
state ^= state >> 17;
|
||||
|
@ -115,32 +143,4 @@ tag_t Thread::GenerateRandomTag() {
|
|||
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
|
||||
|
|
|
@ -16,37 +16,15 @@
|
|||
|
||||
#include "hwasan_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_thread_registry.h"
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
class Thread;
|
||||
|
||||
class ThreadContext : public ThreadContextBase {
|
||||
public:
|
||||
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 Init();
|
||||
thread_return_t ThreadStart();
|
||||
|
||||
uptr stack_top() { return stack_top_; }
|
||||
uptr stack_bottom() { return stack_bottom_; }
|
||||
|
@ -75,9 +53,6 @@ class Thread {
|
|||
return heap_allocations_;
|
||||
}
|
||||
|
||||
void set_context(ThreadContext *context) { context_ = context; }
|
||||
const ThreadContext *context() const { return context_; }
|
||||
|
||||
tag_t GenerateRandomTag();
|
||||
|
||||
int destructor_iterations_;
|
||||
|
@ -107,8 +82,9 @@ class Thread {
|
|||
HwasanThreadLocalMallocStorage malloc_storage_;
|
||||
HeapAllocationsRingBuffer *heap_allocations_;
|
||||
|
||||
u32 tid_;
|
||||
ThreadContext *context_;
|
||||
static void InsertIntoThreadList(Thread *t);
|
||||
static void RemoveFromThreadList(Thread *t);
|
||||
Thread *next_; // All live threads form a linked list.
|
||||
|
||||
u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
|
||||
};
|
||||
|
@ -116,16 +92,11 @@ class Thread {
|
|||
Thread *GetCurrentThread();
|
||||
void SetCurrentThread(Thread *t);
|
||||
|
||||
// Returns the ThreadRegistry singleton.
|
||||
ThreadRegistry &GetThreadRegistry();
|
||||
|
||||
struct ScopedTaggingDisabler {
|
||||
ScopedTaggingDisabler() { GetCurrentThread()->DisableTagging(); }
|
||||
~ScopedTaggingDisabler() { GetCurrentThread()->EnableTagging(); }
|
||||
};
|
||||
|
||||
// Returns the ThreadRegistry singleton.
|
||||
|
||||
} // namespace __hwasan
|
||||
|
||||
#endif // HWASAN_THREAD_H
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sanitizer/hwasan_interface.h>
|
||||
|
||||
void *BoringThread(void *arg) {
|
||||
char * volatile x = (char*)malloc(10);
|
||||
x[5] = 0;
|
||||
free(x);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *UAFThread(void *arg) {
|
||||
char * volatile x = (char*)malloc(10);
|
||||
fprintf(stderr, "ZZZ %p\n", x);
|
||||
free(x);
|
||||
x[5] = 42;
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address
|
||||
// CHECK: WRITE of size 1
|
||||
// CHECK: many-threads-uaf.c:[[@LINE-3]]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
__hwasan_enable_allocator_tagging();
|
||||
pthread_t t;
|
||||
for (int i = 0; i < 1100; i++) {
|
||||
pthread_create(&t, NULL, BoringThread, NULL);
|
||||
pthread_join(t, NULL);
|
||||
}
|
||||
pthread_create(&t, NULL, UAFThread, NULL);
|
||||
pthread_join(t, NULL);
|
||||
}
|
Loading…
Reference in New Issue