tsan: fix a bug in MetaMap::ResetRange

The bug was uncovered by NegativeTests.MmapTest from
data-race-test suite, so port it as well.

llvm-svn: 232032
diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.cc b/compiler-rt/lib/tsan/rtl/tsan_sync.cc
index 3d24633..49c4d15 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_sync.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_sync.cc
@@ -162,8 +162,10 @@
   // freed). Note: we can't simply madvise, because we need to leave a zeroed
   // range (otherwise __tsan_java_move can crash if it encounters a left-over
   // meta objects in java heap).
-  UnmapOrDie((void*)p0, sz0);
-  MmapFixedNoReserve(p0, sz0);
+  uptr metap = (uptr)MemToMeta(p0);
+  uptr metasz = sz0 / kMetaRatio;
+  UnmapOrDie((void*)metap, metasz);
+  MmapFixedNoReserve(metap, metasz);
 }
 
 MBlock* MetaMap::GetBlock(uptr p) {
diff --git a/compiler-rt/test/tsan/mmap_stress.cc b/compiler-rt/test/tsan/mmap_stress.cc
new file mode 100644
index 0000000..5e3904a
--- /dev/null
+++ b/compiler-rt/test/tsan/mmap_stress.cc
@@ -0,0 +1,47 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <errno.h>
+#include <sys/mman.h>
+
+void *SubWorker(void *arg) {
+  (void)arg;
+  const int kMmapSize =  65536;
+  for (int i = 0; i < 500; i++) {
+    int *ptr = (int*)mmap(0, kMmapSize, PROT_READ | PROT_WRITE,
+                          MAP_PRIVATE | MAP_ANON, -1, 0);
+    *ptr = 42;
+    munmap(ptr, kMmapSize);
+  }
+  return 0;
+}
+
+void *Worker1(void *arg) {
+  (void)arg;
+  pthread_t th[4];
+  for (int i = 0; i < 4; i++)
+    pthread_create(&th[i], 0, SubWorker, 0);
+  for (int i = 0; i < 4; i++)
+    pthread_join(th[i], 0);
+  return 0;
+}
+
+void *Worker(void *arg) {
+  (void)arg;
+  pthread_t th[4];
+  for (int i = 0; i < 4; i++)
+    pthread_create(&th[i], 0, Worker1, 0);
+  for (int i = 0; i < 4; i++)
+    pthread_join(th[i], 0);
+  return 0;
+}
+
+int main() {
+  pthread_t th[4];
+  for (int i = 0; i < 4; i++)
+    pthread_create(&th[i], 0, Worker, 0);
+  for (int i = 0; i < 4; i++)
+    pthread_join(th[i], 0);
+  fprintf(stderr, "DONE\n");
+}
+
+// CHECK: DONE