Index: lib/lsan/lsan_interceptors.cc =================================================================== --- lib/lsan/lsan_interceptors.cc +++ lib/lsan/lsan_interceptors.cc @@ -389,10 +389,10 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) { ENSURE_LSAN_INITED; - int tid = ThreadTid((uptr)th); + ThreadContextBase *tctx = ThreadTctx((uptr)th); int res = REAL(pthread_join)(th, ret); if (res == 0) - ThreadJoin(tid); + ThreadJoin(tctx->tid); return res; } Index: lib/lsan/lsan_thread.h =================================================================== --- lib/lsan/lsan_thread.h +++ lib/lsan/lsan_thread.h @@ -49,7 +49,7 @@ void ThreadFinish(); u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); -u32 ThreadTid(uptr uid); +ThreadContextBase *ThreadTctx(uptr uid); u32 GetCurrentThread(); void SetCurrentThread(u32 tid); Index: lib/lsan/lsan_thread.cc =================================================================== --- lib/lsan/lsan_thread.cc +++ lib/lsan/lsan_thread.cc @@ -111,7 +111,7 @@ return false; } -u32 ThreadTid(uptr uid) { +ThreadContextBase *ThreadTctx(uptr uid) { return thread_registry->FindThread(FindThreadByUid, (void*)uid); } Index: lib/sanitizer_common/sanitizer_thread_registry.h =================================================================== --- lib/sanitizer_common/sanitizer_thread_registry.h +++ lib/sanitizer_common/sanitizer_thread_registry.h @@ -50,6 +50,8 @@ u32 parent_tid; ThreadContextBase *next; // For storing thread contexts in a list. + atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished + void SetName(const char *new_name); void SetDead(); @@ -60,6 +62,9 @@ u32 _parent_tid, void *arg); void Reset(); + void SetDestroyed(); + bool GetDestroyed(); + // The following methods may be overriden by subclasses. // Some of them take opaque arg that may be optionally be used // by subclasses. @@ -102,9 +107,9 @@ void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg); typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg); - // Finds a thread using the provided callback. Returns kUnknownTid if no + // Finds a thread using the provided callback. Returns NULL if no // thread is found. - u32 FindThread(FindThreadCallback cb, void *arg); + ThreadContextBase *FindThread(FindThreadCallback cb, void *arg); // Should be guarded by ThreadRegistryLock. Return 0 if no thread // is found. ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, Index: lib/sanitizer_common/sanitizer_thread_registry.cc =================================================================== --- lib/sanitizer_common/sanitizer_thread_registry.cc +++ lib/sanitizer_common/sanitizer_thread_registry.cc @@ -21,6 +21,7 @@ status(ThreadStatusInvalid), detached(false), workerthread(false), parent_tid(0), next(0) { name[0] = '\0'; + atomic_store_relaxed(&thread_destroyed, 0); } ThreadContextBase::~ThreadContextBase() { @@ -88,6 +89,14 @@ OnReset(); } +void ThreadContextBase::SetDestroyed() { + atomic_store(&thread_destroyed, 1, memory_order_release); +} + +bool ThreadContextBase::GetDestroyed() { + return !!atomic_load(&thread_destroyed, memory_order_acquire); +} + // ThreadRegistry implementation. const u32 ThreadRegistry::kUnknownTid = ~0U; @@ -170,14 +179,15 @@ } } -u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { +ThreadContextBase * +ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { BlockingMutexLock l(&mtx_); for (u32 tid = 0; tid < n_contexts_; tid++) { ThreadContextBase *tctx = threads_[tid]; if (tctx != 0 && cb(tctx, arg)) - return tctx->tid; + return tctx; } - return kUnknownTid; + return 0; } ThreadContextBase * Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -868,6 +868,7 @@ } DTLS_Destroy(); cur_thread_finalize(); + thr->tctx->SetDestroyed(); } } // namespace __tsan @@ -982,12 +983,14 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); - int tid = ThreadTid(thr, pc, (uptr)th); + ThreadContextBase *tctx = ThreadTctx(thr, pc, (uptr)th); ThreadIgnoreBegin(thr, pc); int res = BLOCK_REAL(pthread_join)(th, ret); ThreadIgnoreEnd(thr, pc); if (res == 0) { - ThreadJoin(thr, pc, tid); + while (!tctx->GetDestroyed()) + internal_sched_yield(); + ThreadJoin(thr, pc, tctx->tid); } return res; } @@ -996,10 +999,10 @@ TSAN_INTERCEPTOR(int, pthread_detach, void *th) { SCOPED_TSAN_INTERCEPTOR(pthread_detach, th); - int tid = ThreadTid(thr, pc, (uptr)th); + ThreadContextBase *tctx = ThreadTctx(thr, pc, (uptr)th); int res = REAL(pthread_detach)(th); if (res == 0) { - ThreadDetach(thr, pc, tid); + ThreadDetach(thr, pc, tctx->tid); } return res; } Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -757,7 +757,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached); void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread); void ThreadFinish(ThreadState *thr); -int ThreadTid(ThreadState *thr, uptr pc, uptr uid); +ThreadContextBase *ThreadTctx(ThreadState *thr, uptr pc, uptr uid); void ThreadJoin(ThreadState *thr, uptr pc, int tid); void ThreadDetach(ThreadState *thr, uptr pc, int tid); void ThreadFinalize(ThreadState *thr); Index: lib/tsan/rtl/tsan_rtl_thread.cc =================================================================== --- lib/tsan/rtl/tsan_rtl_thread.cc +++ lib/tsan/rtl/tsan_rtl_thread.cc @@ -293,9 +293,10 @@ return false; } -int ThreadTid(ThreadState *thr, uptr pc, uptr uid) { - int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); - DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res); +ThreadContextBase *ThreadTctx(ThreadState *thr, uptr pc, uptr uid) { + ThreadContextBase *res; + res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); + DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res->tid); return res; }