[sanitizer] fix an allocator bug where the allocated memory may overlap with the...
authorKostya Serebryany <kcc@google.com>
Fri, 9 Sep 2016 21:42:33 +0000 (21:42 +0000)
committerKostya Serebryany <kcc@google.com>
Fri, 9 Sep 2016 21:42:33 +0000 (21:42 +0000)
llvm-svn: 281103

compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc

index d6fdcd7..823af7d 100644 (file)
@@ -401,12 +401,12 @@ class SizeClassAllocator64 {
     uptr beg_idx = region->allocated_user;
     uptr end_idx = beg_idx + requested_count * size;
     uptr region_beg = GetRegionBeginBySizeClass(class_id);
-    if (end_idx + size > region->mapped_user) {
+    if (end_idx > region->mapped_user) {
       if (!kUsingConstantSpaceBeg && region->mapped_user == 0)
         region->rand_state = static_cast<u32>(region_beg >> 12);  // From ASLR.
       // Do the mmap for the user memory.
       uptr map_size = kUserMapSize;
-      while (end_idx + size > region->mapped_user + map_size)
+      while (end_idx > region->mapped_user + map_size)
         map_size += kUserMapSize;
       CHECK_GE(region->mapped_user + map_size, end_idx);
       MapWithCallback(region_beg + region->mapped_user, map_size);
@@ -441,7 +441,8 @@ class SizeClassAllocator64 {
       region->mapped_meta += map_size;
     }
     CHECK_LE(region->allocated_meta, region->mapped_meta);
-    if (region->mapped_user + region->mapped_meta > kRegionSize) {
+    if (region->mapped_user + region->mapped_meta >
+        kRegionSize - kFreeArraySize) {
       Printf("%s: Out of memory. Dying. ", SanitizerToolName);
       Printf("The process has exhausted %zuMB for size class %zu.\n",
           kRegionSize / 1024 / 1024, size);
index 30e4aa5..4b5362a 100644 (file)
@@ -931,16 +931,33 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
 
   // ...one man is on a mission to overflow a region with a series of
   // successive allocations.
+
   const uptr kClassID = 107;
-  const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID);
+  const uptr kAllocationSize = SpecialSizeClassMap::Size(kClassID);
   ASSERT_LT(2 * kAllocationSize, kRegionSize);
   ASSERT_GT(3 * kAllocationSize, kRegionSize);
   cache.Allocate(a, kClassID);
   EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID),
                "The process has exhausted");
+
+  const uptr Class2 = 100;
+  const uptr Size2 = SpecialSizeClassMap::Size(Class2);
+  ASSERT_EQ(Size2 * 8, kRegionSize);
+  char *p[7];
+  for (int i = 0; i < 7; i++) {
+    p[i] = (char*)cache.Allocate(a, Class2);
+    fprintf(stderr, "p[%d] %p s = %lx\n", i, (void*)p[i], Size2);
+    p[i][Size2 - 1] = 42;
+    if (i) ASSERT_LT(p[i - 1], p[i]);
+  }
+  EXPECT_DEATH(cache.Allocate(a, Class2), "The process has exhausted");
+  cache.Deallocate(a, Class2, p[0]);
+  cache.Drain(a);
+  ASSERT_EQ(p[6][Size2 - 1], 42);
   a->TestOnlyUnmap();
   delete a;
 }
+
 #endif
 
 TEST(SanitizerCommon, TwoLevelByteMap) {