[compiler-rt] r268782 - tsan: fix a crash

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Fri May 6 12:35:23 PDT 2016


Author: dvyukov
Date: Fri May  6 14:35:22 2016
New Revision: 268782

URL: http://llvm.org/viewvc/llvm-project?rev=268782&view=rev
Log:
tsan: fix a crash

Fixes crash reported in:
https://bugs.chromium.org/p/v8/issues/detail?id=4995

The problem is that we don't have a processor in a free interceptor
during thread exit.

The crash was introduced by introduction of Processors.
However, previously we silently leaked memory which wasn't any better.


Added:
    compiler-rt/trunk/test/tsan/pthread_key.cc
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_mman.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mman.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mman.cc?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mman.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mman.cc Fri May  6 14:35:22 2016
@@ -63,10 +63,29 @@ Allocator *allocator() {
   return reinterpret_cast<Allocator*>(&allocator_placeholder);
 }
 
+struct GlobalProc {
+  Mutex mtx;
+  Processor *proc;
+
+  GlobalProc()
+      : mtx(MutexTypeGlobalProc, StatMtxGlobalProc)
+      , proc(ProcCreate()) {
+  }
+};
+
+static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64);
+GlobalProc *global_proc() {
+  return reinterpret_cast<GlobalProc*>(&global_proc_placeholder);
+}
+
 void InitializeAllocator() {
   allocator()->Init(common_flags()->allocator_may_return_null);
 }
 
+void InitializeAllocatorLate() {
+  new(global_proc()) GlobalProc();
+}
+
 void AllocatorProcStart(Processor *proc) {
   allocator()->InitCache(&proc->alloc_cache);
   internal_allocator()->InitCache(&proc->internal_alloc_cache);
@@ -118,11 +137,29 @@ void *user_calloc(ThreadState *thr, uptr
 }
 
 void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
+  GlobalProc *gp = nullptr;
+  if (thr->proc() == nullptr) {
+    // If we don't have a proc, use the global one.
+    // There is currently only one known case where this path is triggered:
+    //   __interceptor_free
+    //   __nptl_deallocate_tsd
+    //   start_thread
+    //   clone
+    // Ideally, we destroy thread state (and unwire proc) when a thread actually
+    // exits (i.e. when we join/wait it). Then we would not need the global proc
+    gp = global_proc();
+    gp->mtx.Lock();
+    ProcWire(gp->proc, thr);
+  }
   if (ctx && ctx->initialized)
     OnUserFree(thr, pc, (uptr)p, true);
   allocator()->Deallocate(&thr->proc()->alloc_cache, p);
   if (signal)
     SignalUnsafeCall(thr, pc);
+  if (gp) {
+    ProcUnwire(gp->proc, thr);
+    gp->mtx.Unlock();
+  }
 }
 
 void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mman.h Fri May  6 14:35:22 2016
@@ -20,6 +20,7 @@ namespace __tsan {
 const uptr kDefaultAlignment = 16;
 
 void InitializeAllocator();
+void InitializeAllocatorLate();
 void ReplaceSystemMalloc();
 void AllocatorProcStart(Processor *proc);
 void AllocatorProcFinish(Processor *proc);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc Fri May  6 14:35:22 2016
@@ -43,6 +43,7 @@ static MutexType CanLockTab[MutexTypeCou
   /*11 MutexTypeDDetector*/   {},
   /*12 MutexTypeFired*/       {MutexTypeLeaf},
   /*13 MutexTypeRacy*/        {MutexTypeLeaf},
+  /*14 MutexTypeGlobalProc*/  {},
 };
 
 static bool CanLockAdj[MutexTypeCount][MutexTypeCount];

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h Fri May  6 14:35:22 2016
@@ -34,6 +34,7 @@ enum MutexType {
   MutexTypeDDetector,
   MutexTypeFired,
   MutexTypeRacy,
+  MutexTypeGlobalProc,
 
   // This must be the last.
   MutexTypeCount

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Fri May  6 14:35:22 2016
@@ -341,6 +341,7 @@ void Initialize(ThreadState *thr) {
   InitializeDynamicAnnotations();
 #ifndef SANITIZER_GO
   InitializeShadowMemory();
+  InitializeAllocatorLate();
 #endif
   // Setup correct file descriptor for error reports.
   __sanitizer_set_report_path(common_flags()->log_path);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc Fri May  6 14:35:22 2016
@@ -168,6 +168,7 @@ void StatOutput(u64 *stat) {
   name[StatMtxFired]                     = "  FiredSuppressions               ";
   name[StatMtxRacy]                      = "  RacyStacks                      ";
   name[StatMtxFD]                        = "  FD                              ";
+  name[StatMtxGlobalProc]                = "  GlobalProc                      ";
 
   Printf("Statistics:\n");
   for (int i = 0; i < StatCnt; i++)

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h?rev=268782&r1=268781&r2=268782&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h Fri May  6 14:35:22 2016
@@ -173,6 +173,7 @@ enum StatType {
   StatMtxFired,
   StatMtxRacy,
   StatMtxFD,
+  StatMtxGlobalProc,
 
   // This must be the last.
   StatCnt

Added: compiler-rt/trunk/test/tsan/pthread_key.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/pthread_key.cc?rev=268782&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/pthread_key.cc (added)
+++ compiler-rt/trunk/test/tsan/pthread_key.cc Fri May  6 14:35:22 2016
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Extracted from:
+// https://bugs.chromium.org/p/v8/issues/detail?id=4995
+
+#include "test.h"
+
+void* thr(void* arg) {
+  const int N = 32;
+  pthread_key_t keys_[N];
+  for (size_t i = 0; i < N; ++i) {
+    int err = pthread_key_create(&keys_[i], 0);
+    if (err) {
+      fprintf(stderr, "pthread_key_create failed with %d\n", err);
+      exit(1);
+    }
+  }
+  for (size_t i = 0; i < N; i++)
+    pthread_setspecific(keys_[i], (void*)(long)i);
+  for (size_t i = 0; i < N; i++)
+    pthread_key_delete(keys_[i]);
+  return 0;
+}
+
+int main() {
+  for (int i = 0; i < 10; i++) {
+    pthread_t th;
+    pthread_create(&th, 0, thr, 0);
+    pthread_join(th, 0);
+  }
+  pthread_t th[2];
+  pthread_create(&th[0], 0, thr, 0);
+  pthread_create(&th[1], 0, thr, 0);
+  pthread_join(th[0], 0);
+  pthread_join(th[1], 0);
+  fprintf(stderr, "DONE\n");
+  // CHECK: DONE
+}




More information about the llvm-commits mailing list