Index: lib/asan/asan_interceptors.cc =================================================================== --- lib/asan/asan_interceptors.cc +++ lib/asan/asan_interceptors.cc @@ -166,9 +166,13 @@ #include "sanitizer_common/sanitizer_common_syscalls.inc" static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { - AsanThread *t = (AsanThread*)arg; + atomic_uintptr_t *pt = reinterpret_cast(arg); + AsanThread *t = 0; + while ((t = reinterpret_cast( + atomic_load(pt, memory_order_acquire))) == 0) + internal_sched_yield(); SetCurrentThread(t); - return t->ThreadStart(GetTid()); + return t->ThreadStart(GetTid(), pt); } #if ASAN_INTERCEPT_PTHREAD_CREATE @@ -182,12 +186,19 @@ int detached = 0; if (attr != 0) REAL(pthread_attr_getdetachstate)(attr, &detached); - - u32 current_tid = GetCurrentTidOrInvalid(); - AsanThread *t = AsanThread::Create(start_routine, arg); - CreateThreadContextArgs args = { t, &stack }; - asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args); - return REAL(pthread_create)(thread, attr, asan_thread_start, t); + atomic_uintptr_t atomic_t; + atomic_store(&atomic_t, 0, memory_order_relaxed); + int result = REAL(pthread_create)(thread, attr, asan_thread_start, &atomic_t); + if (result == 0) { + u32 current_tid = GetCurrentTidOrInvalid(); + AsanThread *t = AsanThread::Create(start_routine, arg); + CreateThreadContextArgs args = { t, &stack }; + asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args); + atomic_store(&atomic_t, reinterpret_cast(t), memory_order_release); + while (atomic_load(&atomic_t, memory_order_acquire) != 0) + internal_sched_yield(); + } + return result; } #endif // ASAN_INTERCEPT_PTHREAD_CREATE Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -680,7 +680,8 @@ 0, true, 0, &create_main_args); CHECK_EQ(0, main_tid); SetCurrentThread(main_thread); - main_thread->ThreadStart(internal_getpid()); + main_thread->ThreadStart(internal_getpid(), + /* signal_thread_is_registered */ 0); force_interface_symbols(); // no-op. SanitizerInitializeUnwinder(); Index: lib/asan/asan_thread.h =================================================================== --- lib/asan/asan_thread.h +++ lib/asan/asan_thread.h @@ -60,7 +60,8 @@ void Destroy(); void Init(); // Should be called from the thread itself. - thread_return_t ThreadStart(uptr os_id); + thread_return_t ThreadStart(uptr os_id, + atomic_uintptr_t *signal_thread_is_registered); uptr stack_top() { return stack_top_; } uptr stack_bottom() { return stack_bottom_; } Index: lib/asan/asan_thread.cc =================================================================== --- lib/asan/asan_thread.cc +++ lib/asan/asan_thread.cc @@ -155,9 +155,13 @@ AsanPlatformThreadInit(); } -thread_return_t AsanThread::ThreadStart(uptr os_id) { +thread_return_t AsanThread::ThreadStart( + uptr os_id, atomic_uintptr_t *signal_thread_is_registered) { Init(); asanThreadRegistry().StartThread(tid(), os_id, 0); + if (signal_thread_is_registered) + atomic_store(signal_thread_is_registered, 0, memory_order_release); + if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); if (!start_routine_) { Index: lib/lsan/lsan_interceptors.cc =================================================================== --- lib/lsan/lsan_interceptors.cc +++ lib/lsan/lsan_interceptors.cc @@ -215,9 +215,9 @@ int tid = 0; while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); - atomic_store(&p->tid, 0, memory_order_release); SetCurrentThread(tid); ThreadStart(tid, GetTid()); + atomic_store(&p->tid, 0, memory_order_release); return callback(param); } Index: test/lsan/TestCases/leak_check_before_thread_started.cc =================================================================== --- /dev/null +++ test/lsan/TestCases/leak_check_before_thread_started.cc @@ -0,0 +1,15 @@ +// Regression test for http://llvm.org/bugs/show_bug.cgi?id=21621 +// This test relies on timing between threads, so any failures will be flaky. +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -std=c++11 -o %t +// RUN: %run %t +#include +#include + +void func() { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); +} + +int main() { + std::thread(func).detach(); +}