diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp --- a/compiler-rt/lib/hwasan/hwasan.cpp +++ b/compiler-rt/lib/hwasan/hwasan.cpp @@ -186,7 +186,7 @@ uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { Thread *t = GetCurrentThread(); if (!t) { - // the thread is still being created. + // The thread is still being created, or has already been destroyed. size = 0; return; } diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp --- a/compiler-rt/lib/hwasan/hwasan_linux.cpp +++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp @@ -354,8 +354,11 @@ #endif Thread *GetCurrentThread() { - auto *R = (StackAllocationsRingBuffer *)GetCurrentThreadLongPtr(); - return hwasanThreadList().GetThreadByBufferAddress((uptr)(R->Next())); + uptr *ThreadLongPtr = GetCurrentThreadLongPtr(); + if (UNLIKELY(*ThreadLongPtr == 0)) + return nullptr; + auto *R = (StackAllocationsRingBuffer *)ThreadLongPtr; + return hwasanThreadList().GetThreadByBufferAddress((uptr)R->Next()); } struct AccessInfo { diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -90,6 +90,12 @@ if (heap_allocations_) heap_allocations_->Delete(); DTLS_Destroy(); + // Unregister this as the current thread. + // Instrumented code can not run on this thread from this point onwards, but + // malloc/free can still be served. Glibc may call free() very late, after all + // TSD destructors are done. + CHECK_EQ(GetCurrentThread(), this); + *GetCurrentThreadLongPtr() = 0; } void Thread::Print(const char *Prefix) { diff --git a/compiler-rt/test/hwasan/TestCases/libc_thread_freeres.c b/compiler-rt/test/hwasan/TestCases/libc_thread_freeres.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/libc_thread_freeres.c @@ -0,0 +1,22 @@ +// RUN: %clang_hwasan %s -o %t && %env_hwasan_opts=random_tags=1 %run %t +// REQUIRES: stable-runtime + +#include +#include +#include +#include +#include + +void *ThreadFn(void *) { + strerror_l(-1, 0); + __hwasan_enable_allocator_tagging(); + // This will trigger memory deallocation in __strerror_thread_freeres, + // at a point when HwasanThread is already gone. +} + +int main() { + pthread_t t; + pthread_create(&t, NULL, ThreadFn, NULL); + pthread_join(t, NULL); + return 0; +}