Index: lib/asan/asan_errors.cc =================================================================== --- lib/asan/asan_errors.cc +++ lib/asan/asan_errors.cc @@ -182,7 +182,7 @@ 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 @@ ThreadNameWithParenthesis(tid, tname, sizeof(tname))); Printf("%s", d.Default()); stack->Print(); - PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS"); + PrintHintAllocatorCannotReturnNull(); ReportErrorSummary(scariness.GetDescription(), stack); } @@ -212,7 +212,7 @@ 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 @@ #endif Printf("%s", d.Default()); stack->Print(); - PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS"); + PrintHintAllocatorCannotReturnNull(); ReportErrorSummary(scariness.GetDescription(), stack); } @@ -250,7 +250,7 @@ ThreadNameWithParenthesis(tid, tname, sizeof(tname))); Printf("%s", d.Default()); stack->Print(); - PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS"); + PrintHintAllocatorCannotReturnNull(); ReportErrorSummary(scariness.GetDescription(), stack); } @@ -266,7 +266,7 @@ ThreadNameWithParenthesis(tid, tname, sizeof(tname))); Printf("%s", d.Default()); stack->Print(); - PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS"); + PrintHintAllocatorCannotReturnNull(); ReportErrorSummary(scariness.GetDescription(), stack); } @@ -278,7 +278,7 @@ "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 @@ "0x%zx bytes\n", requested_size); Printf("%s", d.Default()); stack->Print(); - PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS"); + PrintHintAllocatorCannotReturnNull(); ReportErrorSummary(scariness.GetDescription(), stack); } Index: lib/sanitizer_common/sanitizer_allocator.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator.h +++ lib/sanitizer_common/sanitizer_allocator.h @@ -34,26 +34,14 @@ 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: lib/sanitizer_common/sanitizer_allocator.cc =================================================================== --- lib/sanitizer_common/sanitizer_allocator.cc +++ lib/sanitizer_common/sanitizer_allocator.cc @@ -140,12 +140,19 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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: lib/sanitizer_common/sanitizer_allocator_local_cache.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -260,8 +260,11 @@ 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: lib/sanitizer_common/sanitizer_allocator_primary64.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_primary64.h +++ lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -118,8 +118,12 @@ // 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: lib/sanitizer_common/sanitizer_allocator_report.cc =================================================================== --- lib/sanitizer_common/sanitizer_allocator_report.cc +++ lib/sanitizer_common/sanitizer_allocator_report.cc @@ -30,8 +30,7 @@ ~ScopedAllocatorErrorReport() { Printf("%s", d.Default()); stack->Print(); - // TODO(alekseyshl): Define SanitizerToolOptionsEnvVarName and use it there. - PrintHintAllocatorCannotReturnNull(""); + PrintHintAllocatorCannotReturnNull(); ReportErrorSummary(error_summary, stack); }