[hwasan] Reset current thread pointer on thread exit.

Summary:
This is necessary to handle calls to free() after __hwasan_thread_exit,
which is possible in glibc.

Also, add a null check to GetCurrentThread, otherwise the logic in
GetThreadByBufferAddress turns it into a non-null value. This means that
all of the checks for GetCurrentThread() != nullptr do not have any
effect at all right now!

Reviewers: pcc, hctim

Subscribers: #sanitizers, llvm-commits

Tags: #sanitizers

Differential Revision: https://reviews.llvm.org/D79608
This commit is contained in:
Evgenii Stepanov 2020-05-07 16:22:21 -07:00
parent fcf10d1908
commit eaea9ed835
4 changed files with 34 additions and 3 deletions

View File

@ -186,7 +186,7 @@ void __sanitizer::BufferedStackTrace::UnwindImpl(
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;
}

View File

@ -354,8 +354,11 @@ void AndroidTestTlsSlot() {}
#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 {

View File

@ -90,6 +90,12 @@ void Thread::Destroy() {
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) {

View File

@ -0,0 +1,22 @@
// RUN: %clang_hwasan %s -o %t && %env_hwasan_opts=random_tags=1 %run %t
// REQUIRES: stable-runtime
#include <pthread.h>
#include <sanitizer/hwasan_interface.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}