Index: compiler-rt/trunk/lib/lsan/lsan_common.cc =================================================================== --- compiler-rt/trunk/lib/lsan/lsan_common.cc +++ compiler-rt/trunk/lib/lsan/lsan_common.cc @@ -201,11 +201,13 @@ continue; } uptr sp; - bool have_registers = - (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); - if (!have_registers) { - Report("Unable to get registers from thread %d.\n"); - // If unable to get SP, consider the entire stack to be reachable. + PtraceRegistersStatus have_registers = + suspended_threads.GetRegistersAndSP(i, registers.data(), &sp); + if (have_registers != REGISTERS_AVAILABLE) { + Report("Unable to get registers from thread %d.\n", os_id); + // If unable to get SP, consider the entire stack to be reachable unless + // GetRegistersAndSP failed with ESRCH. + if (have_registers == REGISTERS_UNAVAILABLE_FATAL) continue; sp = stack_begin; } @@ -253,7 +255,7 @@ if (tls_end > cache_end) ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); } - if (dtls) { + if (dtls && !DTLSInDestruction(dtls)) { for (uptr j = 0; j < dtls->dtv_size; ++j) { uptr dtls_beg = dtls->dtv[j].beg; uptr dtls_end = dtls_beg + dtls->dtv[j].size; @@ -263,6 +265,10 @@ kReachable); } } + } else { + // We are handling a thread with DTLS under destruction. Log about + // this and continue. + LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id); } } } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -20,6 +20,12 @@ namespace __sanitizer { typedef int SuspendedThreadID; +enum PtraceRegistersStatus { + REGISTERS_UNAVAILABLE_FATAL = -1, + REGISTERS_UNAVAILABLE = 0, + REGISTERS_AVAILABLE = 1 +}; + // Holds the list of suspended threads and provides an interface to dump their // register contexts. class SuspendedThreadsList { @@ -30,7 +36,8 @@ CHECK_LT(index, thread_ids_.size()); return thread_ids_[index]; } - int GetRegistersAndSP(uptr index, uptr *buffer, uptr *sp) const; + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; // The buffer in GetRegistersAndSP should be at least this big. static uptr RegisterCount(); uptr thread_count() const { return thread_ids_.size(); } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -493,9 +493,9 @@ #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) -int SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { +PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, + uptr *buffer, + uptr *sp) const { pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; @@ -513,12 +513,16 @@ if (isErr) { VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); - return -1; + // ESRCH means that the given thread is not suspended or already dead. + // Therefore it's unsafe to inspect its data (e.g. walk through stack) and + // we should notify caller about this. + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; } *sp = regs.REG_SP; internal_memcpy(buffer, ®s, sizeof(regs)); - return 0; + return REGISTERS_AVAILABLE; } uptr SuspendedThreadsList::RegisterCount() { Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.h @@ -55,6 +55,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size); DTLS *DTLS_Get(); void DTLS_Destroy(); // Make sure to call this before the thread is destroyed. +// Returns true if DTLS of suspended thread is in destruction process. +bool DTLSInDestruction(DTLS *dtls); } // namespace __sanitizer Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -136,11 +136,17 @@ DTLS *DTLS_Get() { return &dtls; } +bool DTLSInDestruction(DTLS *dtls) { + return dtls->dtv_size == kDestroyedThread; +} + #else void DTLS_on_libc_memalign(void *ptr, uptr size) {} DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; } DTLS *DTLS_Get() { return 0; } void DTLS_Destroy() {} +bool DTLSInDestruction(DTLS *dtls) { UNREACHABLE(); } + #endif // SANITIZER_INTERCEPT_TLS_GET_ADDR } // namespace __sanitizer