forked from OSchip/llvm-project
[Sanitizers] Operator new() interceptors always die on allocation error
Summary: Operator new interceptors behavior is now controlled by their nothrow property as well as by allocator_may_return_null flag value: - allocator_may_return_null=* + new() - die on allocation error - allocator_may_return_null=0 + new(nothrow) - die on allocation error - allocator_may_return_null=1 + new(nothrow) - return null Ideally new() should throw std::bad_alloc exception, but that is not trivial to achieve, hence TODO. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34731 llvm-svn: 306604
This commit is contained in:
parent
7c525903ef
commit
4b450685d3
|
@ -160,7 +160,11 @@ struct QuarantineCallback {
|
|||
}
|
||||
|
||||
void *Allocate(uptr size) {
|
||||
return get_allocator().Allocate(cache_, size, 1);
|
||||
void *res = get_allocator().Allocate(cache_, size, 1);
|
||||
// TODO(alekseys): Consider making quarantine OOM-friendly.
|
||||
if (UNLIKELY(!res))
|
||||
return DieOnFailure::OnOOM();
|
||||
return res;
|
||||
}
|
||||
|
||||
void Deallocate(void *p) {
|
||||
|
@ -524,8 +528,7 @@ struct Allocator {
|
|||
|
||||
// Expects the chunk to already be marked as quarantined by using
|
||||
// AtomicallySetQuarantineFlagIfAllocated.
|
||||
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) {
|
||||
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
|
||||
CHECK_GE(m->alloc_tid, 0);
|
||||
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
|
||||
|
@ -603,7 +606,7 @@ struct Allocator {
|
|||
ReportNewDeleteSizeMismatch(p, delete_size, stack);
|
||||
}
|
||||
|
||||
QuarantineChunk(m, ptr, stack, alloc_type);
|
||||
QuarantineChunk(m, ptr, stack);
|
||||
}
|
||||
|
||||
void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
|
||||
|
|
|
@ -63,12 +63,17 @@ struct nothrow_t {};
|
|||
enum class align_val_t: size_t {};
|
||||
} // namespace std
|
||||
|
||||
#define OPERATOR_NEW_BODY(type) \
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(type, nothrow) \
|
||||
GET_STACK_TRACE_MALLOC;\
|
||||
return asan_memalign(0, size, &stack, type);
|
||||
#define OPERATOR_NEW_BODY_ALIGN(type) \
|
||||
void *res = asan_memalign(0, size, &stack, type);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res;
|
||||
#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
|
||||
GET_STACK_TRACE_MALLOC;\
|
||||
return asan_memalign((uptr)align, size, &stack, type);
|
||||
void *res = asan_memalign((uptr)align, size, &stack, type);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res;
|
||||
|
||||
// On OS X it's not enough to just provide our own 'operator new' and
|
||||
// 'operator delete' implementations, because they're going to be in the
|
||||
|
@ -79,40 +84,42 @@ enum class align_val_t: size_t {};
|
|||
// OS X we need to intercept them using their mangled names.
|
||||
#if !SANITIZER_MAC
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
|
||||
void *operator new(size_t size)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
|
||||
void *operator new[](size_t size)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW); }
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::align_val_t align)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::align_val_t align)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
|
||||
|
||||
#else // SANITIZER_MAC
|
||||
INTERCEPTOR(void *, _Znwm, size_t size) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW);
|
||||
OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR(void *, _Znam, size_t size) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR);
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW);
|
||||
OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR);
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -199,19 +199,26 @@ INTERCEPTOR(int, mprobe, void *ptr) {
|
|||
}
|
||||
#endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
|
||||
|
||||
#define OPERATOR_NEW_BODY \
|
||||
ENSURE_LSAN_INITED; \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
return Allocate(stack, size, 1, kAlwaysClearMemory);
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(nothrow) \
|
||||
ENSURE_LSAN_INITED; \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *res = Allocate(stack, size, 1, kAlwaysClearMemory);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res;
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(true /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(true /*nothrow*/);
|
||||
}
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
ENSURE_LSAN_INITED; \
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "msan.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
|
||||
#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
|
||||
|
||||
|
@ -27,18 +28,25 @@ namespace std {
|
|||
} // namespace std
|
||||
|
||||
|
||||
#define OPERATOR_NEW_BODY \
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(nothrow) \
|
||||
GET_MALLOC_STACK_TRACE; \
|
||||
return MsanReallocate(&stack, 0, size, sizeof(u64), false)
|
||||
void *res = MsanReallocate(&stack, 0, size, sizeof(u64), false);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(true /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(true /*nothrow*/);
|
||||
}
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
GET_MALLOC_STACK_TRACE; \
|
||||
|
|
|
@ -246,11 +246,11 @@ void *ReturnNullOrDieOnFailure::OnOOM() {
|
|||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
||||
void *DieOnFailure::OnBadRequest() {
|
||||
void NORETURN *DieOnFailure::OnBadRequest() {
|
||||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
||||
void *DieOnFailure::OnOOM() {
|
||||
void NORETURN *DieOnFailure::OnOOM() {
|
||||
atomic_store_relaxed(&allocator_out_of_memory, 1);
|
||||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ struct ReturnNullOrDieOnFailure {
|
|||
};
|
||||
// Always dies on the failure.
|
||||
struct DieOnFailure {
|
||||
static void *OnBadRequest();
|
||||
static void *OnOOM();
|
||||
static void NORETURN *OnBadRequest();
|
||||
static void NORETURN *OnOOM();
|
||||
};
|
||||
|
||||
// Returns true if allocator detected OOM condition. Can be used to avoid memory
|
||||
|
|
|
@ -26,13 +26,18 @@ namespace std {
|
|||
struct nothrow_t {};
|
||||
} // namespace std
|
||||
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size) {
|
||||
return scudoMalloc(size, FromNew);
|
||||
void *res = scudoMalloc(size, FromNew);
|
||||
if (UNLIKELY(!res)) DieOnFailure::OnOOM();
|
||||
return res;
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) {
|
||||
return scudoMalloc(size, FromNewArray);
|
||||
void *res = scudoMalloc(size, FromNewArray);
|
||||
if (UNLIKELY(!res)) DieOnFailure::OnOOM();
|
||||
return res;
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// Interceptors for operators new and delete.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "tsan_interceptors.h"
|
||||
|
||||
|
@ -24,13 +25,15 @@ struct nothrow_t {};
|
|||
DECLARE_REAL(void *, malloc, uptr size)
|
||||
DECLARE_REAL(void, free, void *ptr)
|
||||
|
||||
#define OPERATOR_NEW_BODY(mangled_name) \
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(mangled_name, nothrow) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return InternalAlloc(size); \
|
||||
void *p = 0; \
|
||||
{ \
|
||||
SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
|
||||
p = user_alloc(thr, pc, size); \
|
||||
if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \
|
||||
} \
|
||||
invoke_malloc_hook(p, size); \
|
||||
return p;
|
||||
|
@ -38,25 +41,25 @@ DECLARE_REAL(void, free, void *ptr)
|
|||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new(__sanitizer::uptr size);
|
||||
void *operator new(__sanitizer::uptr size) {
|
||||
OPERATOR_NEW_BODY(_Znwm);
|
||||
OPERATOR_NEW_BODY(_Znwm, false /*nothrow*/);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new[](__sanitizer::uptr size);
|
||||
void *operator new[](__sanitizer::uptr size) {
|
||||
OPERATOR_NEW_BODY(_Znam);
|
||||
OPERATOR_NEW_BODY(_Znam, false /*nothrow*/);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
|
||||
void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
|
||||
OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t, true /*nothrow*/);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
|
||||
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
|
||||
OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/);
|
||||
}
|
||||
|
||||
#define OPERATOR_DELETE_BODY(mangled_name) \
|
||||
|
|
|
@ -1,68 +1,97 @@
|
|||
// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
|
||||
// Test the behavior of malloc/calloc/realloc/new when the allocation size is
|
||||
// more than ASan allocator's max allowed one.
|
||||
// By default (allocator_may_return_null=0) the process should crash.
|
||||
// With allocator_may_return_null=1 the allocator should return 0.
|
||||
// With allocator_may_return_null=1 the allocator should return 0, except the
|
||||
// operator new(), which should crash anyway (operator new(std::nothrow) should
|
||||
// return nullptr, indeed).
|
||||
//
|
||||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-cNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-coNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-rNULL
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
|
||||
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL
|
||||
// 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: %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 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Disable stderr buffering. Needed on Windows.
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
|
||||
assert(argc == 2);
|
||||
void *x = 0;
|
||||
if (!strcmp(argv[1], "malloc")) {
|
||||
fprintf(stderr, "malloc:\n");
|
||||
x = malloc(size);
|
||||
}
|
||||
if (!strcmp(argv[1], "calloc")) {
|
||||
fprintf(stderr, "calloc:\n");
|
||||
x = calloc(size / 4, 4);
|
||||
}
|
||||
const char *action = argv[1];
|
||||
fprintf(stderr, "%s:\n", action);
|
||||
|
||||
if (!strcmp(argv[1], "calloc-overflow")) {
|
||||
fprintf(stderr, "calloc-overflow:\n");
|
||||
static const size_t kMaxAllowedMallocSizePlusOne =
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
(1ULL << 40) + 1;
|
||||
#else
|
||||
(3UL << 30) + 1;
|
||||
#endif
|
||||
|
||||
void *x = 0;
|
||||
if (!strcmp(action, "malloc")) {
|
||||
x = malloc(kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "calloc")) {
|
||||
x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4);
|
||||
} else if (!strcmp(action, "calloc-overflow")) {
|
||||
volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
|
||||
size_t kArraySize = 4096;
|
||||
volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
|
||||
x = calloc(kArraySize, kArraySize2);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "realloc")) {
|
||||
fprintf(stderr, "realloc:\n");
|
||||
x = realloc(0, size);
|
||||
}
|
||||
if (!strcmp(argv[1], "realloc-after-malloc")) {
|
||||
fprintf(stderr, "realloc-after-malloc:\n");
|
||||
} else if (!strcmp(action, "realloc")) {
|
||||
x = realloc(0, kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "realloc-after-malloc")) {
|
||||
char *t = (char*)malloc(100);
|
||||
*t = 42;
|
||||
x = realloc(t, size);
|
||||
x = realloc(t, kMaxAllowedMallocSizePlusOne);
|
||||
assert(*t == 42);
|
||||
free(t);
|
||||
} else if (!strcmp(action, "new")) {
|
||||
x = operator new(kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "new-nothrow")) {
|
||||
x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// The NULL pointer is printed differently on different systems, while (long)0
|
||||
// is always the same.
|
||||
fprintf(stderr, "x: %lx\n", (long)x);
|
||||
free(x);
|
||||
|
||||
return x != 0;
|
||||
}
|
||||
|
||||
// CHECK-mCRASH: malloc:
|
||||
// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-cCRASH: calloc:
|
||||
|
@ -73,6 +102,10 @@ int main(int argc, char **argv) {
|
|||
// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-mrCRASH: realloc-after-malloc:
|
||||
// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-nCRASH: new:
|
||||
// CHECK-nCRASH: AddressSanitizer's allocator is terminating the process
|
||||
// CHECK-nnCRASH: new-nothrow:
|
||||
// CHECK-nnCRASH: AddressSanitizer's allocator is terminating the process
|
||||
|
||||
// CHECK-mNULL: malloc:
|
||||
// CHECK-mNULL: x: 0
|
||||
|
@ -84,3 +117,5 @@ int main(int argc, char **argv) {
|
|||
// CHECK-rNULL: x: 0
|
||||
// CHECK-mrNULL: realloc-after-malloc:
|
||||
// CHECK-mrNULL: x: 0
|
||||
// CHECK-nnNULL: new-nothrow:
|
||||
// CHECK-nnNULL: x: 0
|
||||
|
|
|
@ -1,63 +1,98 @@
|
|||
// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
|
||||
// Test the behavior of malloc/calloc/realloc/new when the allocation size is
|
||||
// more than MSan allocator's max allowed one.
|
||||
// By default (allocator_may_return_null=0) the process should crash.
|
||||
// With allocator_may_return_null=1 the allocator should return 0.
|
||||
// With allocator_may_return_null=1 the allocator should return 0, except the
|
||||
// operator new(), which should crash anyway (operator new(std::nothrow) should
|
||||
// return nullptr, indeed).
|
||||
//
|
||||
// RUN: %clangxx_msan -O0 %s -o %t
|
||||
// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-cNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-coNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-rNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
|
||||
// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
int main(int argc, char **argv) {
|
||||
volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
|
||||
assert(argc == 2);
|
||||
char *x = 0;
|
||||
if (!strcmp(argv[1], "malloc")) {
|
||||
fprintf(stderr, "malloc:\n");
|
||||
x = (char*)malloc(size);
|
||||
}
|
||||
if (!strcmp(argv[1], "calloc")) {
|
||||
fprintf(stderr, "calloc:\n");
|
||||
x = (char*)calloc(size / 4, 4);
|
||||
}
|
||||
#include <new>
|
||||
|
||||
if (!strcmp(argv[1], "calloc-overflow")) {
|
||||
fprintf(stderr, "calloc-overflow:\n");
|
||||
int main(int argc, char **argv) {
|
||||
// Disable stderr buffering. Needed on Windows.
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
assert(argc == 2);
|
||||
const char *action = argv[1];
|
||||
fprintf(stderr, "%s:\n", action);
|
||||
|
||||
static const size_t kMaxAllowedMallocSizePlusOne =
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
(8UL << 30) + 1;
|
||||
#else
|
||||
(2UL << 30) + 1;
|
||||
#endif
|
||||
|
||||
void *x = 0;
|
||||
if (!strcmp(action, "malloc")) {
|
||||
x = malloc(kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "calloc")) {
|
||||
x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4);
|
||||
} else if (!strcmp(action, "calloc-overflow")) {
|
||||
volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
|
||||
size_t kArraySize = 4096;
|
||||
volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
|
||||
x = (char*)calloc(kArraySize, kArraySize2);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "realloc")) {
|
||||
fprintf(stderr, "realloc:\n");
|
||||
x = (char*)realloc(0, size);
|
||||
}
|
||||
if (!strcmp(argv[1], "realloc-after-malloc")) {
|
||||
fprintf(stderr, "realloc-after-malloc:\n");
|
||||
x = calloc(kArraySize, kArraySize2);
|
||||
} else if (!strcmp(action, "realloc")) {
|
||||
x = realloc(0, kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "realloc-after-malloc")) {
|
||||
char *t = (char*)malloc(100);
|
||||
*t = 42;
|
||||
x = (char*)realloc(t, size);
|
||||
x = realloc(t, kMaxAllowedMallocSizePlusOne);
|
||||
assert(*t == 42);
|
||||
free(t);
|
||||
} else if (!strcmp(action, "new")) {
|
||||
x = operator new(kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "new-nothrow")) {
|
||||
x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// The NULL pointer is printed differently on different systems, while (long)0
|
||||
// is always the same.
|
||||
fprintf(stderr, "x: %lx\n", (long)x);
|
||||
free(x);
|
||||
|
||||
return x != 0;
|
||||
}
|
||||
|
||||
// CHECK-mCRASH: malloc:
|
||||
// CHECK-mCRASH: MemorySanitizer's allocator is terminating the process
|
||||
// CHECK-cCRASH: calloc:
|
||||
|
@ -68,6 +103,10 @@ int main(int argc, char **argv) {
|
|||
// CHECK-rCRASH: MemorySanitizer's allocator is terminating the process
|
||||
// CHECK-mrCRASH: realloc-after-malloc:
|
||||
// CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process
|
||||
// CHECK-nCRASH: new:
|
||||
// CHECK-nCRASH: MemorySanitizer's allocator is terminating the process
|
||||
// CHECK-nnCRASH: new-nothrow:
|
||||
// CHECK-nnCRASH: MemorySanitizer's allocator is terminating the process
|
||||
|
||||
// CHECK-mNULL: malloc:
|
||||
// CHECK-mNULL: x: 0
|
||||
|
@ -79,3 +118,5 @@ int main(int argc, char **argv) {
|
|||
// CHECK-rNULL: x: 0
|
||||
// CHECK-mrNULL: realloc-after-malloc:
|
||||
// CHECK-mrNULL: x: 0
|
||||
// CHECK-nnNULL: new-nothrow:
|
||||
// CHECK-nnNULL: x: 0
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
// RUN: %clang_scudo %s -o %t
|
||||
// RUN: %clang_scudo %s -lstdc++ -o %t
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s
|
||||
// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t new-nothrow 2>&1
|
||||
// RUN: %run %t usable 2>&1
|
||||
|
||||
// Tests for various edge cases related to sizes, notably the maximum size the
|
||||
|
@ -15,26 +19,38 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <limits>
|
||||
#include <new>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
assert(argc == 2);
|
||||
if (!strcmp(argv[1], "malloc")) {
|
||||
// Currently the maximum size the allocator can allocate is 1ULL<<40 bytes.
|
||||
size_t size = std::numeric_limits<size_t>::max();
|
||||
void *p = malloc(size);
|
||||
const char *action = argv[1];
|
||||
fprintf(stderr, "%s:\n", action);
|
||||
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
static const size_t kMaxAllowedMallocSize = 1ULL << 40;
|
||||
static const size_t kChunkHeaderSize = 16;
|
||||
#else
|
||||
static const size_t kMaxAllowedMallocSize = 2UL << 30;
|
||||
static const size_t kChunkHeaderSize = 8;
|
||||
#endif
|
||||
|
||||
if (!strcmp(action, "malloc")) {
|
||||
void *p = malloc(kMaxAllowedMallocSize);
|
||||
assert(!p);
|
||||
size = (1ULL << 40) - 16;
|
||||
p = malloc(size);
|
||||
p = malloc(kMaxAllowedMallocSize - kChunkHeaderSize);
|
||||
assert(!p);
|
||||
}
|
||||
if (!strcmp(argv[1], "calloc")) {
|
||||
} else if (!strcmp(action, "calloc")) {
|
||||
// Trigger an overflow in calloc.
|
||||
size_t size = std::numeric_limits<size_t>::max();
|
||||
void *p = calloc((size / 0x1000) + 1, 0x1000);
|
||||
assert(!p);
|
||||
}
|
||||
if (!strcmp(argv[1], "usable")) {
|
||||
} else if (!strcmp(action, "new")) {
|
||||
void *p = operator new(kMaxAllowedMallocSize);
|
||||
assert(!p);
|
||||
} else if (!strcmp(action, "new-nothrow")) {
|
||||
void *p = operator new(kMaxAllowedMallocSize, std::nothrow);
|
||||
assert(!p);
|
||||
} else if (!strcmp(action, "usable")) {
|
||||
// Playing with the actual usable size of a chunk.
|
||||
void *p = malloc(1007);
|
||||
assert(p);
|
||||
|
@ -47,7 +63,10 @@ int main(int argc, char **argv)
|
|||
assert(size >= 2014);
|
||||
memset(p, 'B', size);
|
||||
free(p);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,56 +1,90 @@
|
|||
// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
|
||||
// Test the behavior of malloc/calloc/realloc/new when the allocation size is
|
||||
// more than TSan allocator's max allowed one.
|
||||
// By default (allocator_may_return_null=0) the process should crash.
|
||||
// With allocator_may_return_null=1 the allocator should return 0.
|
||||
// With allocator_may_return_null=1 the allocator should return 0, except the
|
||||
// operator new(), which should crash anyway (operator new(std::nothrow) should
|
||||
// return nullptr, indeed).
|
||||
//
|
||||
// RUN: %clangxx_tsan -O0 %s -o %t
|
||||
// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mNULL
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-cNULL
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-coNULL
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-rNULL
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
|
||||
// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \
|
||||
// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
int main(int argc, char **argv) {
|
||||
volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
|
||||
assert(argc == 2);
|
||||
char *x = 0;
|
||||
if (!strcmp(argv[1], "malloc")) {
|
||||
fprintf(stderr, "malloc:\n");
|
||||
x = (char*)malloc(size);
|
||||
}
|
||||
if (!strcmp(argv[1], "calloc")) {
|
||||
fprintf(stderr, "calloc:\n");
|
||||
x = (char*)calloc(size / 4, 4);
|
||||
}
|
||||
#include <new>
|
||||
|
||||
if (!strcmp(argv[1], "calloc-overflow")) {
|
||||
fprintf(stderr, "calloc-overflow:\n");
|
||||
int main(int argc, char **argv) {
|
||||
// Disable stderr buffering. Needed on Windows.
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
assert(argc == 2);
|
||||
const char *action = argv[1];
|
||||
fprintf(stderr, "%s:\n", action);
|
||||
|
||||
static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1;
|
||||
|
||||
void *x = 0;
|
||||
if (!strcmp(action, "malloc")) {
|
||||
x = malloc(kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "calloc")) {
|
||||
x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4);
|
||||
} else if (!strcmp(action, "calloc-overflow")) {
|
||||
volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
|
||||
size_t kArraySize = 4096;
|
||||
volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
|
||||
x = (char*)calloc(kArraySize, kArraySize2);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "realloc")) {
|
||||
fprintf(stderr, "realloc:\n");
|
||||
x = (char*)realloc(0, size);
|
||||
}
|
||||
if (!strcmp(argv[1], "realloc-after-malloc")) {
|
||||
fprintf(stderr, "realloc-after-malloc:\n");
|
||||
x = calloc(kArraySize, kArraySize2);
|
||||
} else if (!strcmp(action, "realloc")) {
|
||||
x = realloc(0, kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "realloc-after-malloc")) {
|
||||
char *t = (char*)malloc(100);
|
||||
*t = 42;
|
||||
x = (char*)realloc(t, size);
|
||||
x = realloc(t, kMaxAllowedMallocSizePlusOne);
|
||||
assert(*t == 42);
|
||||
} else if (!strcmp(action, "new")) {
|
||||
x = operator new(kMaxAllowedMallocSizePlusOne);
|
||||
} else if (!strcmp(action, "new-nothrow")) {
|
||||
x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
fprintf(stderr, "x: %p\n", x);
|
||||
|
||||
// The NULL pointer is printed differently on different systems, while (long)0
|
||||
// is always the same.
|
||||
fprintf(stderr, "x: %lx\n", (long)x);
|
||||
free(x);
|
||||
return x != 0;
|
||||
}
|
||||
|
||||
// CHECK-mCRASH: malloc:
|
||||
// CHECK-mCRASH: ThreadSanitizer's allocator is terminating the process
|
||||
// CHECK-cCRASH: calloc:
|
||||
|
@ -61,4 +95,20 @@ int main(int argc, char **argv) {
|
|||
// CHECK-rCRASH: ThreadSanitizer's allocator is terminating the process
|
||||
// CHECK-mrCRASH: realloc-after-malloc:
|
||||
// CHECK-mrCRASH: ThreadSanitizer's allocator is terminating the process
|
||||
// CHECK-nCRASH: new:
|
||||
// CHECK-nCRASH: ThreadSanitizer's allocator is terminating the process
|
||||
// CHECK-nnCRASH: new-nothrow:
|
||||
// CHECK-nnCRASH: ThreadSanitizer's allocator is terminating the process
|
||||
|
||||
// CHECK-mNULL: malloc:
|
||||
// CHECK-mNULL: x: 0
|
||||
// CHECK-cNULL: calloc:
|
||||
// CHECK-cNULL: x: 0
|
||||
// CHECK-coNULL: calloc-overflow:
|
||||
// CHECK-coNULL: x: 0
|
||||
// CHECK-rNULL: realloc:
|
||||
// CHECK-rNULL: x: 0
|
||||
// CHECK-mrNULL: realloc-after-malloc:
|
||||
// CHECK-mrNULL: x: 0
|
||||
// CHECK-nnNULL: new-nothrow:
|
||||
// CHECK-nnNULL: x: 0
|
||||
|
|
Loading…
Reference in New Issue