diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -17,6 +17,7 @@ #include "hwasan.h" #include "hwasan_checks.h" #include "hwasan_thread.h" +#include "hwasan_thread_list.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" @@ -44,8 +45,6 @@ # include "sanitizer_common/sanitizer_syscalls_netbsd.inc" struct ThreadStartArg { - thread_callback_t callback; - void *param; __sanitizer_sigset_t starting_sigset_; }; @@ -54,47 +53,84 @@ ThreadStartArg A = *reinterpret_cast(arg); SetSigProcMask(&A.starting_sigset_, nullptr); InternalFree(arg); - return A.callback(A.param); + auto self = GetThreadSelf(); + auto args = hwasanThreadArgRetval().GetArgs(self); + void *retval = (*args.routine)(args.arg_retval); + hwasanThreadArgRetval().Finish(self, retval); + return retval; } -INTERCEPTOR(int, pthread_create, void *th, void *attr, +extern "C" { +int pthread_attr_getdetachstate(void *attr, int *v); +} + +INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*callback)(void *), void *param) { EnsureMainThreadIDIsCorrect(); ScopedTaggingDisabler tagging_disabler; + int detached = 0; + if (attr) + pthread_attr_getdetachstate(attr, &detached); ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg)); - A->callback = callback; - A->param = param; ScopedBlockSignals block(&A->starting_sigset_); // ASAN uses the same approach to disable leaks from pthread_create. # if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler lsan_disabler; # endif - int result = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A); + + int result; + hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr { + result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A); + return result ? 0 : *(uptr *)(thread); + }); if (result != 0) InternalFree(A); return result; } -INTERCEPTOR(int, pthread_join, void *t, void **arg) { - return REAL(pthread_join)(t, arg); +INTERCEPTOR(int, pthread_join, void *thread, void **retval) { + int result; + hwasanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_join)(thread, retval); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_detach, void *thread) { - return REAL(pthread_detach)(thread); + int result; + hwasanThreadArgRetval().Detach((uptr)thread, [&]() { + result = REAL(pthread_detach)(thread); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_exit, void *retval) { + auto *t = GetCurrentThread(); + if (t && !t->IsMainThread()) + hwasanThreadArgRetval().Finish(GetThreadSelf(), retval); return REAL(pthread_exit)(retval); } # if SANITIZER_GLIBC INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { - return REAL(pthread_tryjoin_np)(thread, ret); + int result; + hwasanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_tryjoin_np)(thread, ret); + return !result; + }); + return result; } INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, const struct timespec *abstime) { - return REAL(pthread_timedjoin_np)(thread, ret, abstime); + int result; + hwasanThreadArgRetval().Join((uptr)thread, [&]() { + result = REAL(pthread_timedjoin_np)(thread, ret, abstime); + return !result; + }); + return result; } # endif 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 @@ -173,9 +173,15 @@ [os_id](__hwasan::Thread *t) { return t->os_id() == os_id; }); } -void LockThreadRegistry() { __hwasan::hwasanThreadList().Lock(); } +void LockThreadRegistry() { + __hwasan::hwasanThreadList().Lock(); + __hwasan::hwasanThreadArgRetval().Lock(); +} -void UnlockThreadRegistry() { __hwasan::hwasanThreadList().Unlock(); } +void UnlockThreadRegistry() { + __hwasan::hwasanThreadArgRetval().Unlock(); + __hwasan::hwasanThreadList().Unlock(); +} void EnsureMainThreadIDIsCorrect() { __hwasan::EnsureMainThreadIDIsCorrect(); } @@ -202,7 +208,10 @@ InternalMmapVector *ranges) {} void GetThreadExtraStackRangesLocked(InternalMmapVector *ranges) {} -void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) {} +void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { + __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs); +} + void GetRunningThreadsLocked(InternalMmapVector *threads) {} } // namespace __lsan diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.h b/compiler-rt/lib/hwasan/hwasan_thread_list.h --- a/compiler-rt/lib/hwasan/hwasan_thread_list.h +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.h @@ -47,8 +47,8 @@ #include "hwasan_allocator.h" #include "hwasan_flags.h" #include "hwasan_thread.h" - #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_thread_arg_retval.h" namespace __hwasan { @@ -222,5 +222,6 @@ void InitThreadList(uptr storage, uptr size); HwasanThreadList &hwasanThreadList(); +ThreadArgRetval &hwasanThreadArgRetval(); } // namespace __hwasan diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.cpp b/compiler-rt/lib/hwasan/hwasan_thread_list.cpp --- a/compiler-rt/lib/hwasan/hwasan_thread_list.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.cpp @@ -1,10 +1,14 @@ #include "hwasan_thread_list.h" +#include "sanitizer_common/sanitizer_thread_arg_retval.h" + namespace __hwasan { static HwasanThreadList *hwasan_thread_list; +static ThreadArgRetval *thread_data; HwasanThreadList &hwasanThreadList() { return *hwasan_thread_list; } +ThreadArgRetval &hwasanThreadArgRetval() { return *thread_data; } void InitThreadList(uptr storage, uptr size) { CHECK_EQ(hwasan_thread_list, nullptr); @@ -13,6 +17,12 @@ HwasanThreadList)) char thread_list_placeholder[sizeof(HwasanThreadList)]; hwasan_thread_list = new (thread_list_placeholder) HwasanThreadList(storage, size); + + CHECK_EQ(thread_data, nullptr); + + static ALIGNED(alignof( + ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)]; + thread_data = new (thread_data_placeholder) ThreadArgRetval(); } -} // namespace __hwasan +} // namespace __hwasan diff --git a/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp b/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --- a/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp +++ b/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp @@ -6,9 +6,8 @@ // RUN: %run not %t 10 0 0 1 2>&1 | FileCheck %s --check-prefixes=LEAK,LEAK234 // FIXME: Remove "not". There is no leak. -// False LEAK123 is broken for HWASAN. -// False LEAK234 is broken for ASAN, HWASAN, LSAN. -// RUN: %run %if asan %{ not %} %if hwasan %{ not %} %if lsan-standalone %{ not %} %t 10 0 0 0 +// False LEAK234 is broken for ASAN, LSAN. +// RUN: %run %if asan %{ not %} %if lsan-standalone %{ not %} %t 10 0 0 0 #include #include