[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:
Alex Shlyapnikov 2018-03-28 18:22:40 +00:00
parent b873748e15
commit 10f50a44c1
18 changed files with 455 additions and 51 deletions

View File

@ -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

View File

@ -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];

View File

@ -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) \

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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 {

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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}}