Skip to content

Commit

Permalink
[asan] Fixing initialization synchronization on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
zacklj89 committed Dec 19, 2023
1 parent 69d7cd8 commit cd2beca
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
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 @@ -132,6 +132,19 @@ void InstallAtForkHandler();
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();
extern bool replace_intrin_cached;
extern void (*death_callback)(void);
Expand Down
23 changes: 23 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,11 @@ 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.
}
#endif
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
AsanThread *thread = (AsanThread *)MmapOrDie(size, __func__);
Expand Down Expand Up @@ -288,11 +297,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

0 comments on commit cd2beca

Please sign in to comment.