[Sanitizers] Remove OOM/BadRequest allocator error handling policies.
authorAlex Shlyapnikov <alekseys@google.com>
Wed, 20 Jun 2018 17:10:33 +0000 (17:10 +0000)
committerAlex Shlyapnikov <alekseys@google.com>
Wed, 20 Jun 2018 17:10:33 +0000 (17:10 +0000)
Summary:
Remove the generic error nadling policies and handle each allocator error
explicitly. Although more verbose, it allows for more comprehensive, precise
and actionable allocator related failure reports.

This finishes up the series of changes of the particular sanitizer
allocators, improves the internal allocator error reporting and removes
now unused policies.

Reviewers: vitalybuka, cryptoad

Subscribers: kubamracek, delcypher, #sanitizers, llvm-commits

Differential Revision: https://reviews.llvm.org/D48328

llvm-svn: 335147

compiler-rt/lib/asan/asan_errors.cc
compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc
compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
compiler-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h
compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cc

index abbb8e6..6943e67 100644 (file)
@@ -182,7 +182,7 @@ void ErrorCallocOverflow::Print() {
       count, size, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -198,7 +198,7 @@ void ErrorPvallocOverflow::Print() {
       ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -212,7 +212,7 @@ void ErrorInvalidAllocationAlignment::Print() {
       alignment, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -234,7 +234,7 @@ void ErrorInvalidAlignedAllocAlignment::Print() {
 #endif
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -250,7 +250,7 @@ void ErrorInvalidPosixMemalignAlignment::Print() {
       ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -266,7 +266,7 @@ void ErrorAllocationSizeTooBig::Print() {
       ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -278,7 +278,7 @@ void ErrorRssLimitExceeded::Print() {
       "soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb);
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
@@ -290,7 +290,7 @@ void ErrorOutOfMemory::Print() {
       "0x%zx bytes\n", requested_size);
   Printf("%s", d.Default());
   stack->Print();
-  PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+  PrintHintAllocatorCannotReturnNull();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
index 0fdaef1..6bfd5e5 100644 (file)
@@ -140,12 +140,19 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
 
 const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
 
+static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) {
+  SetAllocatorOutOfMemory();
+  Report("FATAL: %s: internal allocator is out of memory trying to allocate "
+         "0x%zx bytes\n", SanitizerToolName, requested_size);
+  Die();
+}
+
 void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {
   if (size + sizeof(u64) < size)
     return nullptr;
   void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment);
   if (UNLIKELY(!p))
-    return DieOnFailure::OnOOM();
+    ReportInternalAllocatorOutOfMemory(size + sizeof(u64));
   ((u64*)p)[0] = kBlockMagic;
   return (char*)p + sizeof(u64);
 }
@@ -160,13 +167,17 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
   CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
   void *p = RawInternalRealloc(addr, size, cache);
   if (UNLIKELY(!p))
-    return DieOnFailure::OnOOM();
+    ReportInternalAllocatorOutOfMemory(size);
   return (char*)p + sizeof(u64);
 }
 
 void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
-  if (UNLIKELY(CheckForCallocOverflow(count, size)))
-    return DieOnFailure::OnBadRequest();
+  if (UNLIKELY(CheckForCallocOverflow(count, size))) {
+    Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) "
+           "cannot be represented in type size_t\n", SanitizerToolName, count,
+           size);
+    Die();
+  }
   void *p = InternalAlloc(count * size, cache);
   if (LIKELY(p))
     internal_memset(p, 0, count * size);
@@ -215,6 +226,8 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
   low_level_alloc_callback = callback;
 }
 
+// Allocator's OOM and other errors handling support.
+
 static atomic_uint8_t allocator_out_of_memory = {0};
 static atomic_uint8_t allocator_may_return_null = {0};
 
@@ -226,15 +239,6 @@ void SetAllocatorOutOfMemory() {
   atomic_store_relaxed(&allocator_out_of_memory, 1);
 }
 
-// Prints error message and kills the program.
-void NORETURN ReportAllocatorCannotReturnNull() {
-  Report("%s's allocator is terminating the process instead of returning 0\n",
-         SanitizerToolName);
-  Report("If you don't like this behavior set allocator_may_return_null=1\n");
-  CHECK(0);
-  Die();
-}
-
 bool AllocatorMayReturnNull() {
   return atomic_load(&allocator_may_return_null, memory_order_relaxed);
 }
@@ -244,32 +248,9 @@ void SetAllocatorMayReturnNull(bool may_return_null) {
                memory_order_relaxed);
 }
 
-void *ReturnNullOrDieOnFailure::OnBadRequest() {
-  if (AllocatorMayReturnNull())
-    return nullptr;
-  ReportAllocatorCannotReturnNull();
-}
-
-void *ReturnNullOrDieOnFailure::OnOOM() {
-  atomic_store_relaxed(&allocator_out_of_memory, 1);
-  if (AllocatorMayReturnNull())
-    return nullptr;
-  ReportAllocatorCannotReturnNull();
-}
-
-void NORETURN *DieOnFailure::OnBadRequest() {
-  ReportAllocatorCannotReturnNull();
-}
-
-void NORETURN *DieOnFailure::OnOOM() {
-  atomic_store_relaxed(&allocator_out_of_memory, 1);
-  ReportAllocatorCannotReturnNull();
-}
-
-// Prints hint message.
-void PrintHintAllocatorCannotReturnNull(const char *options_name) {
+void PrintHintAllocatorCannotReturnNull() {
   Report("HINT: if you don't care about these errors you may set "
-         "%s=allocator_may_return_null=1\n", options_name);
+         "allocator_may_return_null=1\n");
 }
 
 } // namespace __sanitizer
index 0036f80..9655a22 100644 (file)
@@ -34,26 +34,14 @@ extern const char *SecondaryAllocatorName;
 bool AllocatorMayReturnNull();
 void SetAllocatorMayReturnNull(bool may_return_null);
 
-// Allocator failure handling policies:
-// Implements AllocatorMayReturnNull policy, returns null when the flag is set,
-// dies otherwise.
-struct ReturnNullOrDieOnFailure {
-  static void *OnBadRequest();
-  static void *OnOOM();
-};
-// Always dies on the failure.
-struct DieOnFailure {
-  static void NORETURN *OnBadRequest();
-  static void NORETURN *OnOOM();
-};
-
-void PrintHintAllocatorCannotReturnNull(const char *options_name);
-
 // Returns true if allocator detected OOM condition. Can be used to avoid memory
-// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called.
+// hungry operations.
 bool IsAllocatorOutOfMemory();
+// Should be called by a particular allocator when OOM is detected.
 void SetAllocatorOutOfMemory();
 
+void PrintHintAllocatorCannotReturnNull();
+
 // Allocators call these callbacks on mmap/munmap.
 struct NoOpMapUnmapCallback {
   void OnMap(uptr p, uptr size) const { }
index 5bfe83b..1bb8fc2 100644 (file)
@@ -260,8 +260,11 @@ struct SizeClassAllocator32LocalCache {
         class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]);
     // Failure to allocate a batch while releasing memory is non recoverable.
     // TODO(alekseys): Figure out how to do it without allocating a new batch.
-    if (UNLIKELY(!b))
-      DieOnFailure::OnOOM();
+    if (UNLIKELY(!b)) {
+      Report("FATAL: Internal error: %s's allocator failed to allocate a "
+             "transfer batch.\n", SanitizerToolName);
+      Die();
+    }
     b->SetFromArray(&c->batch[first_idx_to_drain], count);
     c->count -= count;
     allocator->DeallocateBatch(&stats_, class_id, b);
index 7a0ab56..6acb4f8 100644 (file)
@@ -118,8 +118,12 @@ class SizeClassAllocator64 {
     // Failure to allocate free array space while releasing memory is non
     // recoverable.
     if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg,
-                                       new_num_freed_chunks)))
-      DieOnFailure::OnOOM();
+                                       new_num_freed_chunks))) {
+      Report("FATAL: Internal error: %s's allocator exhausted the free list "
+             "space for size class %zd (%zd bytes).\n", SanitizerToolName,
+             class_id, ClassIdToSize(class_id));
+      Die();
+    }
     for (uptr i = 0; i < n_chunks; i++)
       free_array[old_num_chunks + i] = chunks[i];
     region->num_freed_chunks = new_num_freed_chunks;
index 4760ba7..e93f90c 100644 (file)
@@ -30,8 +30,7 @@ class ScopedAllocatorErrorReport {
   ~ScopedAllocatorErrorReport() {
     Printf("%s", d.Default());
     stack->Print();
-    // TODO(alekseyshl): Define SanitizerToolOptionsEnvVarName and use it there.
-    PrintHintAllocatorCannotReturnNull("");
+    PrintHintAllocatorCannotReturnNull();
     ReportErrorSummary(error_summary, stack);
   }