Skip to content

Commit

Permalink
[HWSAN] Use ThreadArgRetval in HWSAN
Browse files Browse the repository at this point in the history
Fixes false leaks on thread arg, retval.

Reviewed By: Enna1

Differential Revision: https://reviews.llvm.org/D150166
  • Loading branch information
vitalybuka committed May 11, 2023
1 parent f772dcb commit 68b76af
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 20 deletions.
60 changes: 48 additions & 12 deletions compiler-rt/lib/hwasan/hwasan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -44,8 +45,6 @@ using namespace __hwasan;
# include "sanitizer_common/sanitizer_syscalls_netbsd.inc"

struct ThreadStartArg {
thread_callback_t callback;
void *param;
__sanitizer_sigset_t starting_sigset_;
};

Expand All @@ -54,47 +53,84 @@ static void *HwasanThreadStartFunc(void *arg) {
ThreadStartArg A = *reinterpret_cast<ThreadStartArg *>(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

Expand Down
15 changes: 12 additions & 3 deletions compiler-rt/lib/hwasan/hwasan_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,15 @@ static __hwasan::Thread *GetThreadByOsIDLocked(tid_t os_id) {
[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(); }

Expand All @@ -202,7 +208,10 @@ void GetThreadExtraStackRangesLocked(tid_t os_id,
InternalMmapVector<Range> *ranges) {}
void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) {}

void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {}
void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
__hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs);
}

void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {}

} // namespace __lsan
12 changes: 11 additions & 1 deletion compiler-rt/lib/hwasan/hwasan_thread_list.cpp
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -13,6 +17,12 @@ void InitThreadList(uptr storage, uptr size) {
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
3 changes: 2 additions & 1 deletion compiler-rt/lib/hwasan/hwasan_thread_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -222,5 +222,6 @@ class SANITIZER_MUTEX HwasanThreadList {

void InitThreadList(uptr storage, uptr size);
HwasanThreadList &hwasanThreadList();
ThreadArgRetval &hwasanThreadArgRetval();

} // namespace __hwasan
5 changes: 2 additions & 3 deletions compiler-rt/test/lsan/TestCases/create_thread_leak.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <pthread.h>
#include <stdlib.h>
Expand Down

0 comments on commit 68b76af

Please sign in to comment.