Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions compiler-rt/lib/asan/asan_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,19 @@ void InstallAtExitCheckLeaks();
if (&__asan_on_error) \
__asan_on_error()

// Depending on the loading thread and when ASAN is loaded on Windows,
// race conditions can appear causing incorrect states or internal check
// failures.
//
// From a multithreaded managed environment, if an ASAN instrumented dll
// is loading on a spawned thread, an intercepted function may be called on
// multiple threads while ASAN is still in the process of initialization. This
// can also cause the ASAN thread registry to create the "main" thread after
// another thread, resulting in a TID != 0.
//
// Two threads can also race to initialize ASAN, resulting in either incorrect
// state or internal check failures for init already running.
//
bool AsanInited();
bool AsanInitIsRunning(); // Used to avoid infinite recursion in __asan_init().
extern bool replace_intrin_cached;
Expand Down
51 changes: 45 additions & 6 deletions compiler-rt/lib/asan/asan_rtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,54 @@ static void CheckUnwind() {
}

// -------------------------- Globals --------------------- {{{1
static int asan_inited = 0;
static int asan_init_is_running = 0;
#if SANITIZER_WINDOWS
atomic_uint8_t asan_inited{0};
atomic_uint8_t asan_init_is_running{0};
#else
int asan_inited = 0;
int asan_init_is_running = 0;
#endif

void SetAsanInited(u32 val) { asan_inited = val; }
void SetAsanInited(u32 val) {
#if SANITIZER_WINDOWS
atomic_store(&asan_inited, val, memory_order_release);
#else
asan_inited = val;
#endif
}

void SetAsanInitIsRunning(u32 val) { asan_init_is_running = val; }
void SetAsanInitIsRunning(u32 val) {
#if SANITIZER_WINDOWS
atomic_store(&asan_init_is_running, val, memory_order_release);
#else
asan_init_is_running = val;
#endif
}

bool AsanInited() { return asan_inited == 1; }
bool AsanInited() {
#if SANITIZER_WINDOWS
return atomic_load(&asan_inited, memory_order_acquire) == 1;
#else
return asan_inited == 1;
#endif
}

bool AsanInitIsRunning() { return asan_init_is_running == 1; }
bool AsanInitIsRunning() {
#if SANITIZER_WINDOWS
return atomic_load(&asan_init_is_running, memory_order_acquire) == 1;
#else
return asan_init_is_running == 1;
#endif
}

void CheckAsanInitRunning() {
#if SANITIZER_WINDOWS
while (AsanInitIsRunning()) {
// If ASAN is initializing on another thread, wait for it to finish.
internal_sched_yield();
}
#endif
}

bool replace_intrin_cached;

Expand Down Expand Up @@ -391,6 +429,7 @@ void PrintAddressSpaceLayout() {
}

static void AsanInitInternal() {
CheckAsanInitRunning();
if (LIKELY(AsanInited()))
return;
SanitizerToolName = "AddressSanitizer";
Expand Down
24 changes: 24 additions & 0 deletions compiler-rt/lib/asan/asan_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ namespace __asan {

// AsanThreadContext implementation.

#if SANITIZER_WINDOWS
static atomic_uint8_t main_thread_created{0};
#endif

void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg);
if (args->stack)
Expand Down Expand Up @@ -93,6 +97,12 @@ AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
AsanThread *AsanThread::Create(const void *start_data, uptr data_size,
u32 parent_tid, StackTrace *stack,
bool detached) {
#if SANITIZER_WINDOWS
while (atomic_load(&main_thread_created, memory_order_acquire) == 0) {
// If another thread is trying to be created before the main thread, wait.
internal_sched_yield();
}
#endif
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
AsanThread *thread = (AsanThread *)MmapOrDie(size, __func__);
Expand Down Expand Up @@ -288,11 +298,25 @@ void AsanThread::ThreadStart(tid_t os_id) {
}

AsanThread *CreateMainThread() {
// Depending on the loading thread, specifically in managed scenarios, the main
// thread can be created after other threads on Windows. This ensures we start
// the main thread before those threads.
# if SANITIZER_WINDOWS
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
AsanThread *main_thread = (AsanThread *)MmapOrDie(size, __func__);
AsanThreadContext::CreateThreadContextArgs args = {main_thread, nullptr};
asanThreadRegistry().CreateThread(0, true, kMainTid, &args);
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid());
atomic_store(&main_thread_created, 1, memory_order_release);
# else
AsanThread *main_thread = AsanThread::Create(
/* parent_tid */ kMainTid,
/* stack */ nullptr, /* detached */ true);
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid());
# endif
return main_thread;
}

Expand Down