[lsan] Report unsuspended threads
authorVitaly Buka <vitalybuka@google.com>
Wed, 9 May 2018 23:02:14 +0000 (23:02 +0000)
committerVitaly Buka <vitalybuka@google.com>
Wed, 9 May 2018 23:02:14 +0000 (23:02 +0000)
Summary:
Leak checker needs to suspend all process threads. If we have some running
thread in registry but not suspended we can have false leak report. So we will
report this case here for future debugging.

Reviewers: eugenis

Subscribers: kubamracek, llvm-commits

Differential Revision: https://reviews.llvm.org/D46663

llvm-svn: 331936

compiler-rt/lib/asan/asan_thread.cc
compiler-rt/lib/lsan/lsan_common.cc
compiler-rt/lib/lsan/lsan_common.h
compiler-rt/lib/lsan/lsan_thread.cc

index ad81512..4a8779f 100644 (file)
@@ -477,6 +477,11 @@ void UnlockThreadRegistry() {
   __asan::asanThreadRegistry().Unlock();
 }
 
+ThreadRegistry *GetThreadRegistryLocked() {
+  __asan::asanThreadRegistry().CheckLocked();
+  return &__asan::asanThreadRegistry();
+}
+
 void EnsureMainThreadIDIsCorrect() {
   __asan::EnsureMainThreadIDIsCorrect();
 }
index bdc825d..eaa5cad 100644 (file)
 #include "lsan_common.h"
 
 #include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_suppressions.h"
-#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 
 #if CAN_SANITIZE_LEAKS
@@ -526,11 +527,36 @@ struct CheckForLeaksParam {
   LeakReport leak_report;
 };
 
+static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
+  const InternalMmapVector<tid_t> &suspended_threads =
+      *(const InternalMmapVector<tid_t> *)arg;
+  if (tctx->status == ThreadStatusRunning) {
+    uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
+                                tctx->os_id, CompareLess<int>());
+    if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
+      Report("Running thread %d was not suspended. False leaks are possible.\n",
+             tctx->os_id);
+  };
+}
+
+static void ReportUnsuspendedThreads(
+    const SuspendedThreadsList &suspended_threads) {
+  InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
+  for (uptr i = 0; i < suspended_threads.ThreadCount(); ++i)
+    threads[i] = suspended_threads.GetThreadID(i);
+
+  Sort(threads.data(), threads.size());
+
+  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      &ReportIfNotSuspended, &threads);
+}
+
 static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
                                   void *arg) {
   CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
   CHECK(param);
   CHECK(!param->success);
+  ReportUnsuspendedThreads(suspended_threads);
   ClassifyAllChunks(suspended_threads);
   ForEachChunk(CollectLeaksCb, &param->leak_report);
   // Clean up for subsequent leak checks. This assumes we did not overwrite any
index 2bffed4..1d1e1e4 100644 (file)
@@ -47,6 +47,7 @@
 
 namespace __sanitizer {
 class FlagParser;
+class ThreadRegistry;
 struct DTLS;
 }
 
@@ -204,6 +205,7 @@ bool WordIsPoisoned(uptr addr);
 // Wrappers for ThreadRegistry access.
 void LockThreadRegistry();
 void UnlockThreadRegistry();
+ThreadRegistry *GetThreadRegistryLocked();
 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
                            uptr *cache_end, DTLS **dtls);
index 4404c8c..a25aff3 100644 (file)
@@ -155,4 +155,9 @@ void UnlockThreadRegistry() {
   thread_registry->Unlock();
 }
 
+ThreadRegistry *GetThreadRegistryLocked() {
+  thread_registry->CheckLocked();
+  return thread_registry;
+}
+
 } // namespace __lsan