count, size, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
alignment, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
#endif
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
"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);
}
"0x%zx bytes\n", requested_size);
Printf("%s", d.Default());
stack->Print();
- PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(scariness.GetDescription(), stack);
}
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);
}
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);
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};
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);
}
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
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 { }
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);
// 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;
~ScopedAllocatorErrorReport() {
Printf("%s", d.Default());
stack->Print();
- // TODO(alekseyshl): Define SanitizerToolOptionsEnvVarName and use it there.
- PrintHintAllocatorCannotReturnNull("");
+ PrintHintAllocatorCannotReturnNull();
ReportErrorSummary(error_summary, stack);
}