[compiler-rt] r276377 - [sanitizer] allocator: introduce kUseSeparateSizeClassForBatch (false by default). When true, it will cause all TransferBatches to be allocated on a separate dedicated size class, which improves security and may potentially simplify memory reclamation. However in the current state this may cause up to 3% extra memory usage. Subsequent changes should bring this overhead down

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 21 18:13:13 PDT 2016


Author: kcc
Date: Thu Jul 21 20:13:13 2016
New Revision: 276377

URL: http://llvm.org/viewvc/llvm-project?rev=276377&view=rev
Log:
[sanitizer] allocator: introduce kUseSeparateSizeClassForBatch (false by default). When true, it will cause all TransferBatches to be allocated on a separate dedicated size class, which improves security and may potentially simplify memory reclamation. However in the current state this may cause up to 3% extra memory usage. Subsequent changes should bring this overhead down

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_local_cache.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_size_class_map.h
    compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_local_cache.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_local_cache.h?rev=276377&r1=276376&r2=276377&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_local_cache.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_local_cache.h Thu Jul 21 20:13:13 2016
@@ -92,8 +92,8 @@ struct SizeClassAllocatorLocalCache {
   // For small size classes allocates the batch from the allocator.
   // For large size classes simply returns b.
   Batch *CreateBatch(uptr class_id, SizeClassAllocator *allocator, Batch *b) {
-    if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
-      return (Batch*)Allocate(allocator, SizeClassMap::ClassID(sizeof(Batch)));
+    if (uptr batch_class_id = SizeClassMap::SizeClassForTransferBatch(class_id))
+      return (Batch*)Allocate(allocator, batch_class_id);
     return b;
   }
 
@@ -101,8 +101,8 @@ struct SizeClassAllocatorLocalCache {
   // For small size classes deallocates b to the allocator.
   // Does notthing for large size classes.
   void DestroyBatch(uptr class_id, SizeClassAllocator *allocator, Batch *b) {
-    if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
-      Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
+    if (uptr batch_class_id = SizeClassMap::SizeClassForTransferBatch(class_id))
+      Deallocate(allocator, batch_class_id, b);
   }
 
   NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_size_class_map.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_size_class_map.h?rev=276377&r1=276376&r2=276377&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_size_class_map.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator_size_class_map.h Thu Jul 21 20:13:13 2016
@@ -32,6 +32,9 @@
 //  - kMaxNumCached is the maximal number of chunks per size class.
 //  - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
 //
+// There is one extra size class kBatchClassID that is used for allocating
+// objects of TransferBatch type when kUseSeparateSizeClassForBatch is true.
+//
 // Part of output of SizeClassMap::Print():
 // c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
 // c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
@@ -97,11 +100,22 @@ class SizeClassMap {
     uptr count;
     void *batch[kMaxNumCached];
   };
-  COMPILER_CHECK((sizeof(TransferBatch) & (sizeof(TransferBatch) - 1)) == 0);
+  static const uptr kBatchSize = sizeof(TransferBatch);
+  COMPILER_CHECK((kBatchSize & (kBatchSize - 1)) == 0);
+
+  // If true, all TransferBatch objects are allocated from kBatchClassID
+  // size class (except for those that are needed for kBatchClassID itself).
+  // The goal is to have TransferBatches in a totally different region of RAM
+  // to improve security and allow more efficient RAM reclamation.
+  // This is experimental and may currently increase memory usage by up to 3%
+  // in extreme cases.
+  static const bool kUseSeparateSizeClassForBatch = false;
+
 
   static const uptr kMaxSize = 1UL << kMaxSizeLog;
   static const uptr kNumClasses =
-      kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
+      kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1 + 1;
+  static const uptr kBatchClassID = kNumClasses - 1;
   COMPILER_CHECK(kNumClasses >= 32 && kNumClasses <= 256);
   static const uptr kNumClassesRounded =
       kNumClasses == 32  ? 32 :
@@ -111,6 +125,8 @@ class SizeClassMap {
   static uptr Size(uptr class_id) {
     if (class_id <= kMidClass)
       return kMinSize * class_id;
+    if (class_id == kBatchClassID)
+      return kBatchSize;
     class_id -= kMidClass;
     uptr t = kMidSize << (class_id >> S);
     return t + (t >> S) * (class_id & M);
@@ -144,6 +160,8 @@ class SizeClassMap {
       uptr p = prev_s ? (d * 100 / prev_s) : 0;
       uptr l = s ? MostSignificantSetBitIndex(s) : 0;
       uptr cached = MaxCached(i) * s;
+      if (i == kBatchClassID)
+        d = l = p = 0;
       Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
              "cached: %zd %zd; id %zd\n",
              i, Size(i), d, p, l, MaxCached(i), cached, ClassID(s));
@@ -153,18 +171,23 @@ class SizeClassMap {
     Printf("Total cached: %zd\n", total_cached);
   }
 
-  static bool SizeClassRequiresSeparateTransferBatch(uptr class_id) {
-    return Size(class_id) < sizeof(TransferBatch) -
-        sizeof(uptr) * (kMaxNumCached - MaxCached(class_id));
+  static uptr SizeClassForTransferBatch(uptr class_id) {
+    if (kUseSeparateSizeClassForBatch)
+      return class_id == kBatchClassID ? 0 : kBatchClassID;
+    if (Size(class_id) < sizeof(TransferBatch) -
+        sizeof(uptr) * (kMaxNumCached - MaxCached(class_id)))
+      return ClassID(sizeof(TransferBatch));
+    return 0;
   }
 
   static void Validate() {
     for (uptr c = 1; c < kNumClasses; c++) {
+      if (c == kBatchClassID) continue;
       // Printf("Validate: c%zd\n", c);
       uptr s = Size(c);
       CHECK_NE(s, 0U);
       CHECK_EQ(ClassID(s), c);
-      if (c != kNumClasses - 1)
+      if (c != kBatchClassID - 1 && c != kNumClasses - 1)
         CHECK_EQ(ClassID(s + 1), c + 1);
       CHECK_EQ(ClassID(s - 1), c);
       if (c)

Modified: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc?rev=276377&r1=276376&r2=276377&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc Thu Jul 21 20:13:13 2016
@@ -60,6 +60,25 @@ static void thread_dtor(void *v) {
   allocator.SwallowCache(&cache);
 }
 
+static size_t GetRss() {
+  if (FILE *f = fopen("/proc/self/statm", "r")) {
+    size_t size = 0, rss = 0;
+    fscanf(f, "%zd %zd", &size, &rss);
+    fclose(f);
+    return rss << 12;  // rss is in pages.
+  }
+  return 0;
+}
+
+struct AtExit {
+  ~AtExit() {
+    allocator.PrintStats();
+    Printf("RSS: %zdM\n", GetRss() >> 20);
+  }
+};
+
+static AtExit at_exit;
+
 static void NOINLINE thread_init() {
   if (!global_inited) {
     global_inited = true;




More information about the llvm-commits mailing list