[tsan] minor enhancements in the new tsan allocator and a test malloc replacement library that can be linked to any program to replace malloc (tested on spec2006)

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@160436 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/sanitizer_common/sanitizer_allocator64.h b/lib/sanitizer_common/sanitizer_allocator64.h
index e78710d..ca2321c 100644
--- a/lib/sanitizer_common/sanitizer_allocator64.h
+++ b/lib/sanitizer_common/sanitizer_allocator64.h
@@ -152,6 +152,11 @@
     return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
   }
 
+  uptr GetActuallyAllocatedSize(void *p) {
+    CHECK(PointerIsMine(p));
+    return SizeClassMap::Size(GetSizeClass(p));
+  }
+
   uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
 
   void *GetMetaData(void *p) {
@@ -354,6 +359,10 @@
     return false;
   }
 
+  uptr GetActuallyAllocatedSize(void *p) {
+    return RoundUpMapSize(GetHeader(p)->size) - kPageSize;
+  }
+
   // At least kPageSize/2 metadata bytes is available.
   void *GetMetaData(void *p) {
     return GetHeader(p) + 1;
@@ -397,7 +406,9 @@
     secondary_.Init();
   }
 
-  void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
+  void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
+                 bool cleared = false) {
+    if (size == 0) return 0;
     CHECK_GT(size, 0);
     if (alignment > 8)
       size = RoundUpTo(size, alignment);
@@ -408,16 +419,37 @@
       res = secondary_.Allocate(size, alignment);
     if (alignment > 8)
       CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
+    if (cleared)
+      internal_memset(res, 0, size);
     return res;
   }
 
   void Deallocate(AllocatorCache *cache, void *p) {
+    if (!p) return;
     if (primary_.PointerIsMine(p))
       cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
     else
       secondary_.Deallocate(p);
   }
 
+  void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
+                   uptr alignment) {
+    if (!p)
+      return Allocate(cache, new_size, alignment);
+    if (!new_size) {
+      Deallocate(cache, p);
+      return 0;
+    }
+    CHECK(PointerIsMine(p));
+    uptr old_size = GetActuallyAllocatedSize(p);
+    uptr memcpy_size = Min(new_size, old_size);
+    void *new_p = Allocate(cache, new_size, alignment);
+    if (new_p)
+      internal_memcpy(new_p, p, memcpy_size);
+    Deallocate(cache, p);
+    return new_p;
+  }
+
   bool PointerIsMine(void *p) {
     if (primary_.PointerIsMine(p))
       return true;
@@ -430,6 +462,12 @@
     return secondary_.GetMetaData(p);
   }
 
+  uptr GetActuallyAllocatedSize(void *p) {
+    if (primary_.PointerIsMine(p))
+      return primary_.GetActuallyAllocatedSize(p);
+    return secondary_.GetActuallyAllocatedSize(p);
+  }
+
   uptr TotalMemoryUsed() {
     return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
   }
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
index cbb71db..1410f26 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
@@ -74,6 +74,7 @@
         void *x = a.Allocate(size, 1);
         allocated.push_back(x);
         CHECK(a.PointerIsMine(x));
+        CHECK_GE(a.GetActuallyAllocatedSize(x), size);
         uptr class_id = a.GetSizeClass(x);
         CHECK_EQ(class_id, SCMap::ClassID(size));
         uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
@@ -164,6 +165,7 @@
   // Allocate some more, also add metadata.
   for (int i = 0; i < kNumAllocs; i++) {
     void *x = a.Allocate(size, 1);
+    CHECK_GE(a.GetActuallyAllocatedSize(x), size);
     uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
     *meta = i;
     allocated[i] = x;
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc b/lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc
new file mode 100644
index 0000000..e0c85dc
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc
@@ -0,0 +1,84 @@
+//===-- sanitizer_allocator64_testlib.cc ----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Malloc replacement library based on CombinedAllocator.
+// The primary purpose of this file is an end-to-end integration test
+// for CombinedAllocator.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator64.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+namespace {
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize = 0x10000000000;  // 1T.
+
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 16,
+  DefaultSizeClassMap> PrimaryAllocator;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator::kNumClasses,
+  PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+          SecondaryAllocator> Allocator;
+
+static THREADLOCAL AllocatorCache cache;
+static Allocator allocator;
+
+static int inited = 0;
+
+__attribute__((constructor))
+void Init() {
+  if (inited) return;
+  inited = true;  // this must happen before any threads are created.
+  allocator.Init();
+}
+
+}  // namespace
+
+namespace __sanitizer {
+void NORETURN Die() {
+  _exit(77);
+}
+void NORETURN CheckFailed(const char *file, int line, const char *cond,
+                          u64 v1, u64 v2) {
+  fprintf(stderr, "CheckFailed: %s:%d %s (%lld %lld)\n",
+          file, line, cond, v1, v2);
+  Die();
+}
+}
+
+#if 1
+extern "C" {
+void *malloc(size_t size) {
+  assert(inited);
+  return allocator.Allocate(&cache, size, 8);
+}
+
+void free(void *p) {
+  assert(inited);
+  allocator.Deallocate(&cache, p);
+}
+
+void *calloc(size_t nmemb, size_t size) {
+  assert(inited);
+  return allocator.Allocate(&cache, nmemb * size, 8, /*cleared=*/true);
+}
+
+void *realloc(void *p, size_t new_size) {
+  assert(inited);
+  return allocator.Reallocate(&cache, p, new_size, 8);
+}
+
+void *memalign() { assert(0); }
+int posix_memalign() { assert(0); }
+void *valloc() { assert(0); }
+void *pvalloc() { assert(0); }
+}
+#endif
diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old
index 7bcc84e..2091f61 100644
--- a/lib/tsan/Makefile.old
+++ b/lib/tsan/Makefile.old
@@ -17,7 +17,7 @@
 GTEST_BUILD_DIR=$(GTEST_ROOT)/build
 GTEST_LIB=$(GTEST_BUILD_DIR)/gtest-all.o
 
-SANITIZER_COMMON_TESTS_SRC=$(wildcard ../sanitizer_common/tests/*.cc)
+SANITIZER_COMMON_TESTS_SRC=$(wildcard ../sanitizer_common/tests/*_test.cc)
 SANITIZER_COMMON_TESTS_OBJ=$(patsubst %.cc,%.o,$(SANITIZER_COMMON_TESTS_SRC))
 RTL_TEST_SRC=$(wildcard rtl_tests/*.cc)
 RTL_TEST_OBJ=$(patsubst %.cc,%.o,$(RTL_TEST_SRC))
@@ -43,7 +43,7 @@
 libtsan:
 	$(MAKE) -C rtl -f Makefile.old DEBUG=$(DEBUG)
 
-%.o: %.cc $(UNIT_TEST_HDR) libtsan
+%.o: %.cc $(UNIT_TEST_HDR) $(LIBTSAN)
 	$(CXX) $(CXXFLAGS) $(CFLAGS) $(INCLUDES) -o $@ -c $<
 
 tsan_test: $(UNIT_TEST_OBJ) $(RTL_TEST_OBJ) \