forked from OSchip/llvm-project
[ASan] Report proper ASan error on allocator failures instead of CHECK(0)-ing
Summary: Currently many allocator specific errors (OOM, for example) are reported as a text message and CHECK(0) termination, not stack, no details, not too helpful nor informative. To improve the situation, ASan detailed errors were defined and reported under the appropriate conditions. Issue: https://github.com/google/sanitizers/issues/887 Reviewers: eugenis Subscribers: kubamracek, delcypher, #sanitizers, llvm-commits Differential Revision: https://reviews.llvm.org/D44404 llvm-svn: 328722
This commit is contained in:
parent
b873748e15
commit
10f50a44c1
|
@ -134,8 +134,9 @@ struct AsanChunk: ChunkBase {
|
|||
};
|
||||
|
||||
struct QuarantineCallback {
|
||||
explicit QuarantineCallback(AllocatorCache *cache)
|
||||
: cache_(cache) {
|
||||
QuarantineCallback(AllocatorCache *cache, BufferedStackTrace *stack)
|
||||
: cache_(cache),
|
||||
stack_(stack) {
|
||||
}
|
||||
|
||||
void Recycle(AsanChunk *m) {
|
||||
|
@ -168,7 +169,7 @@ struct QuarantineCallback {
|
|||
void *res = get_allocator().Allocate(cache_, size, 1);
|
||||
// TODO(alekseys): Consider making quarantine OOM-friendly.
|
||||
if (UNLIKELY(!res))
|
||||
return DieOnFailure::OnOOM();
|
||||
ReportOutOfMemory(size, stack_);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -176,7 +177,9 @@ struct QuarantineCallback {
|
|||
get_allocator().Deallocate(cache_, p);
|
||||
}
|
||||
|
||||
AllocatorCache *cache_;
|
||||
private:
|
||||
AllocatorCache* const cache_;
|
||||
BufferedStackTrace* const stack_;
|
||||
};
|
||||
|
||||
typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine;
|
||||
|
@ -397,8 +400,11 @@ struct Allocator {
|
|||
AllocType alloc_type, bool can_fill) {
|
||||
if (UNLIKELY(!asan_inited))
|
||||
AsanInitFromRtl();
|
||||
if (RssLimitExceeded())
|
||||
return ReturnNullOrDieOnFailure::OnOOM();
|
||||
if (RssLimitExceeded()) {
|
||||
if (AllocatorMayReturnNull())
|
||||
return nullptr;
|
||||
ReportRssLimitExceeded(stack);
|
||||
}
|
||||
Flags &fl = *flags();
|
||||
CHECK(stack);
|
||||
const uptr min_alignment = SHADOW_GRANULARITY;
|
||||
|
@ -431,9 +437,13 @@ struct Allocator {
|
|||
}
|
||||
CHECK(IsAligned(needed_size, min_alignment));
|
||||
if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
|
||||
Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
|
||||
(void*)size);
|
||||
return ReturnNullOrDieOnFailure::OnBadRequest();
|
||||
if (AllocatorMayReturnNull()) {
|
||||
Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
|
||||
(void*)size);
|
||||
return nullptr;
|
||||
}
|
||||
ReportAllocationSizeTooBig(size, needed_size, kMaxAllowedMallocSize,
|
||||
stack);
|
||||
}
|
||||
|
||||
AsanThread *t = GetCurrentThread();
|
||||
|
@ -446,8 +456,12 @@ struct Allocator {
|
|||
AllocatorCache *cache = &fallback_allocator_cache;
|
||||
allocated = allocator.Allocate(cache, needed_size, 8);
|
||||
}
|
||||
if (UNLIKELY(!allocated))
|
||||
return ReturnNullOrDieOnFailure::OnOOM();
|
||||
if (UNLIKELY(!allocated)) {
|
||||
SetAllocatorOutOfMemory();
|
||||
if (AllocatorMayReturnNull())
|
||||
return nullptr;
|
||||
ReportOutOfMemory(size, stack);
|
||||
}
|
||||
|
||||
if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
|
||||
// Heap poisoning is enabled, but the allocator provides an unpoisoned
|
||||
|
@ -583,13 +597,13 @@ struct Allocator {
|
|||
if (t) {
|
||||
AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
|
||||
AllocatorCache *ac = GetAllocatorCache(ms);
|
||||
quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), m,
|
||||
m->UsedSize());
|
||||
quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac, stack), m,
|
||||
m->UsedSize());
|
||||
} else {
|
||||
SpinMutexLock l(&fallback_mutex);
|
||||
AllocatorCache *ac = &fallback_allocator_cache;
|
||||
quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), m,
|
||||
m->UsedSize());
|
||||
quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac, stack),
|
||||
m, m->UsedSize());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -660,8 +674,11 @@ struct Allocator {
|
|||
}
|
||||
|
||||
void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
|
||||
if (UNLIKELY(CheckForCallocOverflow(size, nmemb)))
|
||||
return ReturnNullOrDieOnFailure::OnBadRequest();
|
||||
if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
|
||||
if (AllocatorMayReturnNull())
|
||||
return nullptr;
|
||||
ReportCallocOverflow(nmemb, size, stack);
|
||||
}
|
||||
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
|
||||
// If the memory comes from the secondary allocator no need to clear it
|
||||
// as it comes directly from mmap.
|
||||
|
@ -677,9 +694,9 @@ struct Allocator {
|
|||
ReportFreeNotMalloced((uptr)ptr, stack);
|
||||
}
|
||||
|
||||
void CommitBack(AsanThreadLocalMallocStorage *ms) {
|
||||
void CommitBack(AsanThreadLocalMallocStorage *ms, BufferedStackTrace *stack) {
|
||||
AllocatorCache *ac = GetAllocatorCache(ms);
|
||||
quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac));
|
||||
quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac, stack));
|
||||
allocator.SwallowCache(ac);
|
||||
}
|
||||
|
||||
|
@ -739,17 +756,19 @@ struct Allocator {
|
|||
return AsanChunkView(m1);
|
||||
}
|
||||
|
||||
void Purge() {
|
||||
void Purge(BufferedStackTrace *stack) {
|
||||
AsanThread *t = GetCurrentThread();
|
||||
if (t) {
|
||||
AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
|
||||
quarantine.DrainAndRecycle(GetQuarantineCache(ms),
|
||||
QuarantineCallback(GetAllocatorCache(ms)));
|
||||
QuarantineCallback(GetAllocatorCache(ms),
|
||||
stack));
|
||||
}
|
||||
{
|
||||
SpinMutexLock l(&fallback_mutex);
|
||||
quarantine.DrainAndRecycle(&fallback_quarantine_cache,
|
||||
QuarantineCallback(&fallback_allocator_cache));
|
||||
QuarantineCallback(&fallback_allocator_cache,
|
||||
stack));
|
||||
}
|
||||
|
||||
allocator.ForceReleaseToOS();
|
||||
|
@ -836,7 +855,8 @@ AsanChunkView FindHeapChunkByAllocBeg(uptr addr) {
|
|||
}
|
||||
|
||||
void AsanThreadLocalMallocStorage::CommitBack() {
|
||||
instance.CommitBack(this);
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
instance.CommitBack(this, &stack);
|
||||
}
|
||||
|
||||
void PrintInternalAllocatorStats() {
|
||||
|
@ -883,7 +903,9 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
|
|||
uptr PageSize = GetPageSizeCached();
|
||||
if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
|
||||
errno = errno_ENOMEM;
|
||||
return ReturnNullOrDieOnFailure::OnBadRequest();
|
||||
if (AllocatorMayReturnNull())
|
||||
return nullptr;
|
||||
ReportPvallocOverflow(size, stack);
|
||||
}
|
||||
// pvalloc(0) should allocate one page.
|
||||
size = size ? RoundUpTo(size, PageSize) : PageSize;
|
||||
|
@ -895,7 +917,9 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
|
|||
AllocType alloc_type) {
|
||||
if (UNLIKELY(!IsPowerOfTwo(alignment))) {
|
||||
errno = errno_EINVAL;
|
||||
return ReturnNullOrDieOnFailure::OnBadRequest();
|
||||
if (AllocatorMayReturnNull())
|
||||
return nullptr;
|
||||
ReportInvalidAllocationAlignment(alignment, stack);
|
||||
}
|
||||
return SetErrnoOnNull(
|
||||
instance.Allocate(size, alignment, stack, alloc_type, true));
|
||||
|
@ -904,11 +928,13 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
|
|||
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
BufferedStackTrace *stack) {
|
||||
if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
|
||||
ReturnNullOrDieOnFailure::OnBadRequest();
|
||||
return errno_EINVAL;
|
||||
if (AllocatorMayReturnNull())
|
||||
return errno_EINVAL;
|
||||
ReportInvalidPosixMemalignAlignment(alignment, stack);
|
||||
}
|
||||
void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true);
|
||||
if (UNLIKELY(!ptr))
|
||||
// OOM error is already taken care of by Allocate.
|
||||
return errno_ENOMEM;
|
||||
CHECK(IsAligned((uptr)ptr, alignment));
|
||||
*memptr = ptr;
|
||||
|
@ -1054,7 +1080,8 @@ uptr __sanitizer_get_allocated_size(const void *p) {
|
|||
}
|
||||
|
||||
void __sanitizer_purge_allocator() {
|
||||
instance.Purge();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
instance.Purge(&stack);
|
||||
}
|
||||
|
||||
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
|
|
|
@ -172,6 +172,106 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {
|
|||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorCallocOverflow::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
char tname[128];
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: calloc parameters overflow: count * size "
|
||||
"(%zd * %zd) cannot be represented in type size_t (thread T%d%s)\n",
|
||||
count, size, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorPvallocOverflow::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
char tname[128];
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: pvalloc parameters overflow: size 0x%zx "
|
||||
"rounded up to system page size 0x%zx cannot be represented in type "
|
||||
"size_t (thread T%d%s)\n",
|
||||
size, GetPageSizeCached(), tid,
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorInvalidAllocationAlignment::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
char tname[128];
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: invalid allocation alignment: %zd, "
|
||||
"alignment must be a power of two (thread T%d%s)\n",
|
||||
alignment, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorInvalidPosixMemalignAlignment::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
char tname[128];
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: invalid alignment requested in posix_memalign: "
|
||||
"%zd, alignment must be a power of two and a multiple of sizeof(void*) "
|
||||
"== %zd (thread T%d%s)\n",
|
||||
alignment, sizeof(void*), tid, // NOLINT
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorAllocationSizeTooBig::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
char tname[128];
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: requested allocation size 0x%zx (0x%zx after "
|
||||
"adjustments for alignment, red zones etc.) exceeds maximum supported "
|
||||
"size of 0x%zx (thread T%d%s)\n",
|
||||
user_size, total_size, max_size, tid,
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorRssLimitExceeded::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: specified RSS limit exceeded, currently set to "
|
||||
"soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb);
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorOutOfMemory::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: allocator is out of memory trying to allocate "
|
||||
"0x%zx bytes\n", requested_size);
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
}
|
||||
|
||||
void ErrorStringFunctionMemoryRangesOverlap::Print() {
|
||||
Decorator d;
|
||||
char bug_type[100];
|
||||
|
|
|
@ -23,6 +23,10 @@ namespace __asan {
|
|||
struct ErrorBase {
|
||||
ErrorBase() = default;
|
||||
explicit ErrorBase(u32 tid_) : tid(tid_) {}
|
||||
ErrorBase(u32 tid_, int initial_score, const char *reason) : tid(tid_) {
|
||||
scariness.Clear();
|
||||
scariness.Scare(initial_score, reason);
|
||||
}
|
||||
ScarinessScoreBase scariness;
|
||||
u32 tid;
|
||||
};
|
||||
|
@ -164,6 +168,105 @@ struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
|
|||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorCallocOverflow : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
uptr count;
|
||||
uptr size;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorCallocOverflow() = default;
|
||||
ErrorCallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_,
|
||||
uptr size_)
|
||||
: ErrorBase(tid, 10, "calloc-overflow"),
|
||||
stack(stack_),
|
||||
count(count_),
|
||||
size(size_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorPvallocOverflow : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
uptr size;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorPvallocOverflow() = default;
|
||||
ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_)
|
||||
: ErrorBase(tid, 10, "pvalloc-overflow"),
|
||||
stack(stack_),
|
||||
size(size_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorInvalidAllocationAlignment : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
uptr alignment;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorInvalidAllocationAlignment() = default;
|
||||
ErrorInvalidAllocationAlignment(u32 tid, BufferedStackTrace *stack_,
|
||||
uptr alignment_)
|
||||
: ErrorBase(tid, 10, "invalid-allocation-alignment"),
|
||||
stack(stack_),
|
||||
alignment(alignment_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorInvalidPosixMemalignAlignment : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
uptr alignment;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorInvalidPosixMemalignAlignment() = default;
|
||||
ErrorInvalidPosixMemalignAlignment(u32 tid, BufferedStackTrace *stack_,
|
||||
uptr alignment_)
|
||||
: ErrorBase(tid, 10, "invalid-posix-memalign-alignment"),
|
||||
stack(stack_),
|
||||
alignment(alignment_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorAllocationSizeTooBig : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
uptr user_size;
|
||||
uptr total_size;
|
||||
uptr max_size;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorAllocationSizeTooBig() = default;
|
||||
ErrorAllocationSizeTooBig(u32 tid, BufferedStackTrace *stack_,
|
||||
uptr user_size_, uptr total_size_, uptr max_size_)
|
||||
: ErrorBase(tid, 10, "allocation-size-too-big"),
|
||||
stack(stack_),
|
||||
user_size(user_size_),
|
||||
total_size(total_size_),
|
||||
max_size(max_size_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorRssLimitExceeded : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorRssLimitExceeded() = default;
|
||||
ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_)
|
||||
: ErrorBase(tid, 10, "rss-limit-exceeded"),
|
||||
stack(stack_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorOutOfMemory : ErrorBase {
|
||||
const BufferedStackTrace *stack;
|
||||
uptr requested_size;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorOutOfMemory() = default;
|
||||
ErrorOutOfMemory(u32 tid, BufferedStackTrace *stack_, uptr requested_size_)
|
||||
: ErrorBase(tid, 10, "out-of-memory"),
|
||||
stack(stack_),
|
||||
requested_size(requested_size_) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase {
|
||||
// ErrorStringFunctionMemoryRangesOverlap doesn't own the stack trace.
|
||||
const BufferedStackTrace *stack;
|
||||
|
@ -300,6 +403,13 @@ struct ErrorGeneric : ErrorBase {
|
|||
macro(AllocTypeMismatch) \
|
||||
macro(MallocUsableSizeNotOwned) \
|
||||
macro(SanitizerGetAllocatedSizeNotOwned) \
|
||||
macro(CallocOverflow) \
|
||||
macro(PvallocOverflow) \
|
||||
macro(InvalidAllocationAlignment) \
|
||||
macro(InvalidPosixMemalignAlignment) \
|
||||
macro(AllocationSizeTooBig) \
|
||||
macro(RssLimitExceeded) \
|
||||
macro(OutOfMemory) \
|
||||
macro(StringFunctionMemoryRangesOverlap) \
|
||||
macro(StringFunctionSizeOverflow) \
|
||||
macro(BadParamsToAnnotateContiguousContainer) \
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
|
||||
#include "interception/interception.h"
|
||||
|
@ -67,16 +68,16 @@ struct nothrow_t {};
|
|||
enum class align_val_t: size_t {};
|
||||
} // namespace std
|
||||
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(type, nothrow) \
|
||||
GET_STACK_TRACE_MALLOC;\
|
||||
void *res = asan_memalign(0, size, &stack, type);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
|
||||
return res;
|
||||
#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
|
||||
GET_STACK_TRACE_MALLOC;\
|
||||
void *res = asan_memalign((uptr)align, size, &stack, type);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
|
||||
return res;
|
||||
|
||||
// On OS X it's not enough to just provide our own 'operator new' and
|
||||
|
|
|
@ -254,6 +254,54 @@ void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
|
|||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportInvalidAllocationAlignment(uptr alignment,
|
||||
BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack,
|
||||
alignment);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportInvalidPosixMemalignAlignment(uptr alignment,
|
||||
BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack,
|
||||
alignment);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
|
||||
BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size,
|
||||
total_size, max_size);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportRssLimitExceeded(BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
||||
const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2,
|
||||
|
|
|
@ -58,6 +58,16 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
|||
void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
|
||||
void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack);
|
||||
void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack);
|
||||
void ReportInvalidAllocationAlignment(uptr alignment,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportInvalidPosixMemalignAlignment(uptr alignment,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportRssLimitExceeded(BufferedStackTrace *stack);
|
||||
void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack);
|
||||
void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
||||
const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2,
|
||||
|
|
|
@ -218,6 +218,10 @@ bool IsAllocatorOutOfMemory() {
|
|||
return atomic_load_relaxed(&allocator_out_of_memory);
|
||||
}
|
||||
|
||||
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",
|
||||
|
@ -258,4 +262,10 @@ void NORETURN *DieOnFailure::OnOOM() {
|
|||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
||||
// Prints hint message.
|
||||
void PrintHintAllocatorCannotReturnNull(const char *options_name) {
|
||||
Report("HINT: if you don't care about these errors you may set "
|
||||
"%s=allocator_may_return_null=1\n", options_name);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -43,9 +43,12 @@ struct DieOnFailure {
|
|||
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.
|
||||
bool IsAllocatorOutOfMemory();
|
||||
void SetAllocatorOutOfMemory();
|
||||
|
||||
// Allocators call these callbacks on mmap/munmap.
|
||||
struct NoOpMapUnmapCallback {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
void *p = aligned_alloc(17, 100);
|
||||
// CHECK: ERROR: AddressSanitizer: invalid allocation alignment: 17
|
||||
// CHECK: {{#0 0x.* in .*aligned_alloc}}
|
||||
// CHECK: {{#1 0x.* in main .*aligned_alloc-alignment.cc:}}[[@LINE-3]]
|
||||
// CHECK: SUMMARY: AddressSanitizer: invalid-allocation-alignment
|
||||
|
||||
printf("pointer after failed aligned_alloc: %zd\n", (size_t)p);
|
||||
// CHECK-NULL: pointer after failed aligned_alloc: 0
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -84,5 +84,5 @@ int main(int argc, char **argv) {
|
|||
// CHECK-REALLOC: realloc:
|
||||
// CHECK-MALLOC-REALLOC: realloc-after-malloc:
|
||||
|
||||
// CHECK-CRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-CRASH: SUMMARY: AddressSanitizer: out-of-memory
|
||||
// CHECK-NULL: x: 0
|
||||
|
|
|
@ -38,4 +38,7 @@ int main(int argc, char *argv[]) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// CHECK: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK: {{ERROR: AddressSanitizer: pvalloc parameters overflow: size .* rounded up to system page size .* cannot be represented in type size_t}}
|
||||
// CHECK: {{#0 0x.* in .*pvalloc}}
|
||||
// CHECK: {{#1 0x.* in main .*pvalloc-overflow.cc:}}
|
||||
// CHECK: SUMMARY: AddressSanitizer: pvalloc-overflow
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
void *p = reinterpret_cast<void*>(42);
|
||||
int res = posix_memalign(&p, 17, 100);
|
||||
// CHECK: ERROR: AddressSanitizer: invalid alignment requested in posix_memalign: 17
|
||||
// CHECK: {{#0 0x.* in .*posix_memalign}}
|
||||
// CHECK: {{#1 0x.* in main .*posix_memalign-alignment.cc:}}[[@LINE-3]]
|
||||
// CHECK: SUMMARY: AddressSanitizer: invalid-posix-memalign-alignment
|
||||
|
||||
printf("pointer after failed posix_memalign: %zd\n", (size_t)p);
|
||||
// CHECK-NULL: pointer after failed posix_memalign: 42
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -8,5 +8,5 @@ int main() {
|
|||
while (true) {
|
||||
void *ptr = malloc(200 * 1024 * 1024); // 200MB
|
||||
}
|
||||
// CHECK: allocator is terminating the process instead of returning 0
|
||||
// CHECK: SUMMARY: AddressSanitizer: out-of-memory
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH-OOM
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \
|
||||
|
@ -98,19 +98,21 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
// CHECK-mCRASH: malloc:
|
||||
// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-mCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-cCRASH: calloc:
|
||||
// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-cCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-coCRASH: calloc-overflow:
|
||||
// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-coCRASH: SUMMARY: AddressSanitizer: calloc-overflow
|
||||
// CHECK-rCRASH: realloc:
|
||||
// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-rCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-mrCRASH: realloc-after-malloc:
|
||||
// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-mrCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-nCRASH: new:
|
||||
// CHECK-nCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-nCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-nCRASH-OOM: new:
|
||||
// CHECK-nCRASH-OOM: SUMMARY: AddressSanitizer: out-of-memory
|
||||
// CHECK-nnCRASH: new-nothrow:
|
||||
// CHECK-nnCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-nnCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
|
||||
// CHECK-mNULL: malloc:
|
||||
// CHECK-mNULL: errno: 12
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
void *p = calloc(-1, 1000);
|
||||
// CHECK: {{ERROR: AddressSanitizer: calloc parameters overflow: count \* size \(.* \* 1000\) cannot be represented in type size_t}}
|
||||
// CHECK: {{#0 0x.* in .*calloc}}
|
||||
// CHECK: {{#1 0x.* in main .*calloc-overflow.cc:}}[[@LINE-3]]
|
||||
// CHECK: SUMMARY: AddressSanitizer: calloc-overflow
|
||||
|
||||
printf("calloc returned: %zu\n", (size_t)p);
|
||||
// CHECK-NULL: calloc returned: 0
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const size_t kMaxAllowedMallocSizePlusOne =
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
(1ULL << 40) + 1;
|
||||
#else
|
||||
(3UL << 30) + 1;
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
void *p = malloc(kMaxAllowedMallocSizePlusOne);
|
||||
// CHECK: {{ERROR: AddressSanitizer: requested allocation size .* \(.* after adjustments for alignment, red zones etc\.\) exceeds maximum supported size}}
|
||||
// CHECK: {{#0 0x.* in .*malloc}}
|
||||
// CHECK: {{#1 0x.* in main .*malloc-size-too-big.cc:}}[[@LINE-3]]
|
||||
// CHECK: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
|
||||
printf("malloc returned: %zu\n", (size_t)p);
|
||||
// CHECK-NULL: malloc returned: 0
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -30,12 +30,16 @@
|
|||
// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: %env_lsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH-OOM
|
||||
// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
|
||||
// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL
|
||||
|
||||
// TODO(alekseyshl): Enable it back for standalone LSan mode when CHECK(0) in
|
||||
// LSan allocator are converted to proper errors (see D44404 for the reference).
|
||||
// REQUIRES: asan
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
@ -98,19 +102,21 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
// CHECK-mCRASH: malloc:
|
||||
// CHECK-mCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-mCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-cCRASH: calloc:
|
||||
// CHECK-cCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-cCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-coCRASH: calloc-overflow:
|
||||
// CHECK-coCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-coCRASH: SUMMARY: AddressSanitizer: calloc-overflow
|
||||
// CHECK-rCRASH: realloc:
|
||||
// CHECK-rCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-rCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-mrCRASH: realloc-after-malloc:
|
||||
// CHECK-mrCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-mrCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-nCRASH: new:
|
||||
// CHECK-nCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-nCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
// CHECK-nCRASH-OOM: new:
|
||||
// CHECK-nCRASH-OOM: SUMMARY: AddressSanitizer: out-of-memory
|
||||
// CHECK-nnCRASH: new-nothrow:
|
||||
// CHECK-nnCRASH: Sanitizer's allocator is terminating the process
|
||||
// CHECK-nnCRASH: SUMMARY: AddressSanitizer: allocation-size-too-big
|
||||
|
||||
// CHECK-mNULL: malloc:
|
||||
// CHECK-mNULL: errno: 12
|
||||
|
|
|
@ -65,4 +65,4 @@ int main() {
|
|||
// CHECK_MAY_RETURN_0: allocating 128 times
|
||||
// CHECK_MAY_RETURN_0: Some of the malloc calls returned non-null: 128
|
||||
// CHECK_MAY_RETURN_0: allocating 256 times
|
||||
// CHECK_MAY_RETURN_0: allocator is terminating the process instead of returning
|
||||
// CHECK_MAY_RETURN_0: {{SUMMARY: .*Sanitizer: rss-limit-exceeded}}
|
||||
|
|
Loading…
Reference in New Issue