tsan: store sync objects in memory block headers + delete them when the block is freed


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@161959 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/sanitizer_common/sanitizer_allocator64.h b/lib/sanitizer_common/sanitizer_allocator64.h
index 4bc8c11..a8ea6f8 100644
--- a/lib/sanitizer_common/sanitizer_allocator64.h
+++ b/lib/sanitizer_common/sanitizer_allocator64.h
@@ -145,10 +145,11 @@
     region->free_list.append_front(free_list);
   }
 
-  bool PointerIsMine(void *p) {
+  static bool PointerIsMine(void *p) {
     return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
   }
-  uptr GetSizeClass(void *p) {
+
+  static uptr GetSizeClass(void *p) {
     return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
   }
 
diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc
index caabaf6..b87eb0d 100644
--- a/lib/tsan/rtl/tsan_mman.cc
+++ b/lib/tsan/rtl/tsan_mman.cc
@@ -50,7 +50,7 @@
   MBlock *b = (MBlock*)allocator()->GetMetaData(p);
   b->size = sz;
   if (CTX() && CTX()->initialized) {
-    MemoryResetRange(thr, pc, (uptr)p, sz);
+    MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
   }
   DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
   SignalUnsafeCall(thr, pc);
@@ -62,6 +62,18 @@
   CHECK_NE(p, (void*)0);
   DPrintf("#%d: free(%p)\n", thr->tid, p);
   MBlock *b = (MBlock*)allocator()->GetMetaData(p);
+  if (b->head)   {
+    Lock l(&b->mtx);
+    for (SyncVar *s = b->head; s;) {
+      SyncVar *res = s;
+      s = s->next;
+      StatInc(thr, StatSyncDestroyed);
+      res->mtx.Lock();
+      res->mtx.Unlock();
+      DestroyAndFree(res);
+    }
+    b->head = 0;
+  }
   if (CTX() && CTX()->initialized && thr->in_rtl == 1) {
     MemoryRangeFreed(thr, pc, (uptr)p, b->size);
   }
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index abb5a2a..2f8e785 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -47,6 +47,31 @@
 
 SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
                              uptr addr, bool write_lock) {
+#ifndef TSAN_GO
+  if (PrimaryAllocator::PointerIsMine((void*)addr)) {
+    MBlock *b = user_mblock(thr, (void*)addr);
+    Lock l(&b->mtx);
+    SyncVar *res = 0;
+    for (res = b->head; res; res = res->next) {
+      if (res->addr == addr)
+        break;
+    }
+    if (res == 0) {
+      StatInc(thr, StatSyncCreated);
+      void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
+      res = new(mem) SyncVar(addr);
+      res->creation_stack.ObtainCurrent(thr, pc);
+      res->next = b->head;
+      b->head = res;
+    }
+    if (write_lock)
+      res->mtx.Lock();
+    else
+      res->mtx.ReadLock();
+    return res;
+  }
+#endif
+
   Part *p = &tab_[PartIdx(addr)];
   {
     ReadLock l(&p->mtx);
@@ -86,6 +111,32 @@
 }
 
 SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
+#ifndef TSAN_GO
+  if (PrimaryAllocator::PointerIsMine((void*)addr)) {
+    MBlock *b = user_mblock(thr, (void*)addr);
+    SyncVar *res = 0;
+    {
+      Lock l(&b->mtx);
+      SyncVar **prev = &b->head;
+      res = *prev;
+      while (res) {
+        if (res->addr == addr) {
+          *prev = res->next;
+          break;
+        }
+        prev = &res->next;
+        res = *prev;
+      }
+    }
+    if (res) {
+      StatInc(thr, StatSyncDestroyed);
+      res->mtx.Lock();
+      res->mtx.Unlock();
+    }
+    return res;
+  }
+#endif
+
   Part *p = &tab_[PartIdx(addr)];
   SyncVar *res = 0;
   {