Index: lib/tsan/rtl/tsan_mman.cc =================================================================== --- lib/tsan/rtl/tsan_mman.cc +++ lib/tsan/rtl/tsan_mman.cc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_placement_new.h" @@ -150,13 +151,24 @@ OutputReport(thr, rep); } +static constexpr uptr kMaxAllowedMallocSize = 1ull << 40; + void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { - if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize) { + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportAllocationSizeTooBig(sz, kMaxAllowedMallocSize, &stack); + } void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); - if (UNLIKELY(p == 0)) - return ReturnNullOrDieOnFailure::OnOOM(); + if (UNLIKELY(!p)) { + SetAllocatorOutOfMemory(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportOutOfMemory(sz, &stack); + } if (ctx && ctx->initialized) OnUserAlloc(thr, pc, (uptr)p, sz, true); if (signal) @@ -178,8 +190,12 @@ } void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { - if (UNLIKELY(CheckForCallocOverflow(size, n))) - return SetErrnoOnNull(ReturnNullOrDieOnFailure::OnBadRequest()); + if (UNLIKELY(CheckForCallocOverflow(size, n))) { + if (AllocatorMayReturnNull()) + return SetErrnoOnNull(nullptr); + GET_STACK_TRACE_FATAL(thr, pc); + ReportCallocOverflow(n, size, &stack); + } void *p = user_alloc_internal(thr, pc, n * size); if (p) internal_memset(p, 0, n * size); @@ -224,7 +240,10 @@ void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) { if (UNLIKELY(!IsPowerOfTwo(align))) { errno = errno_EINVAL; - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportInvalidAllocationAlignment(align, &stack); } return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); } @@ -232,11 +251,14 @@ int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, uptr sz) { if (UNLIKELY(!CheckPosixMemalignAlignment(align))) { - ReturnNullOrDieOnFailure::OnBadRequest(); - return errno_EINVAL; + if (AllocatorMayReturnNull()) + return errno_EINVAL; + GET_STACK_TRACE_FATAL(thr, pc); + ReportInvalidPosixMemalignAlignment(align, &stack); } void *ptr = user_alloc_internal(thr, pc, sz, align); if (UNLIKELY(!ptr)) + // OOM error is already taken care of by user_alloc_internal. return errno_ENOMEM; CHECK(IsAligned((uptr)ptr, align)); *memptr = ptr; @@ -246,7 +268,10 @@ void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) { if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) { errno = errno_EINVAL; - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportInvalidAlignedAllocAlignment(sz, align, &stack); } return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); } @@ -259,7 +284,10 @@ uptr PageSize = GetPageSizeCached(); if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) { errno = errno_ENOMEM; - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportPvallocOverflow(sz, &stack); } // pvalloc(0) should allocate one page. sz = sz ? RoundUpTo(sz, PageSize) : PageSize; Index: lib/tsan/rtl/tsan_new_delete.cc =================================================================== --- lib/tsan/rtl/tsan_new_delete.cc +++ lib/tsan/rtl/tsan_new_delete.cc @@ -13,8 +13,10 @@ //===----------------------------------------------------------------------===// #include "interception/interception.h" #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "tsan_interceptors.h" +#include "tsan_rtl.h" using namespace __tsan; // NOLINT @@ -34,7 +36,10 @@ { \ SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ p = user_alloc(thr, pc, size); \ - if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ + if (!nothrow && UNLIKELY(!p)) { \ + GET_STACK_TRACE_FATAL(thr, pc); \ + ReportOutOfMemory(size, &stack); \ + } \ } \ invoke_malloc_hook(p, size); \ return p; @@ -46,7 +51,10 @@ { \ SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ p = user_memalign(thr, pc, (uptr)align, size); \ - if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ + if (!nothrow && UNLIKELY(!p)) { \ + GET_STACK_TRACE_FATAL(thr, pc); \ + ReportOutOfMemory(size, &stack); \ + } \ } \ invoke_malloc_hook(p, size); \ return p; Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -650,6 +650,10 @@ ExtractTagFromStack(stack, tag); } +#define GET_STACK_TRACE_FATAL(thr, pc) \ + VarSizeStackTrace stack; \ + ObtainCurrentStack(thr, pc, &stack); \ + stack.ReverseOrder(); #if TSAN_COLLECT_STATS void StatAggregate(u64 *dst, u64 *src); Index: lib/tsan/rtl/tsan_stack_trace.h =================================================================== --- lib/tsan/rtl/tsan_stack_trace.h +++ lib/tsan/rtl/tsan_stack_trace.h @@ -27,6 +27,10 @@ ~VarSizeStackTrace(); void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); + // Reverses the current stack trace order, the top frame goes to the bottom, + // the last frame goes to the top. + void ReverseOrder(); + private: void ResizeBuffer(uptr new_size); Index: lib/tsan/rtl/tsan_stack_trace.cc =================================================================== --- lib/tsan/rtl/tsan_stack_trace.cc +++ lib/tsan/rtl/tsan_stack_trace.cc @@ -43,4 +43,9 @@ trace_buffer[cnt] = extra_top_pc; } +void VarSizeStackTrace::ReverseOrder() { + for (u32 i = 0; i < (size >> 1); i++) + Swap(trace_buffer[i], trace_buffer[size - 1 - i]); +} + } // namespace __tsan Index: lib/tsan/tests/unit/tsan_mman_test.cc =================================================================== --- lib/tsan/tests/unit/tsan_mman_test.cc +++ lib/tsan/tests/unit/tsan_mman_test.cc @@ -153,29 +153,12 @@ EXPECT_NE(p, (void*)0); EXPECT_EQ(page_size, __sanitizer_get_allocated_size(p)); user_free(thr, 0, p); - - EXPECT_DEATH(p = user_pvalloc(thr, 0, (uptr)-(page_size - 1)), - "allocator is terminating the process instead of returning 0"); - EXPECT_DEATH(p = user_pvalloc(thr, 0, (uptr)-1), - "allocator is terminating the process instead of returning 0"); } #if !SANITIZER_DEBUG // EXPECT_DEATH clones a thread with 4K stack, // which is overflown by tsan memory accesses functions in debug mode. -TEST(Mman, CallocOverflow) { - ThreadState *thr = cur_thread(); - uptr pc = 0; - size_t kArraySize = 4096; - volatile size_t kMaxSizeT = std::numeric_limits::max(); - volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - volatile void *p = NULL; - EXPECT_DEATH(p = user_calloc(thr, pc, kArraySize, kArraySize2), - "allocator is terminating the process instead of returning 0"); - EXPECT_EQ(0L, p); -} - TEST(Mman, Memalign) { ThreadState *thr = cur_thread(); @@ -183,12 +166,16 @@ EXPECT_NE(p, (void*)0); user_free(thr, 0, p); + // TODO(alekseyshl): Remove this death test when memalign is verified by + // tests in sanitizer_common. p = NULL; EXPECT_DEATH(p = user_memalign(thr, 0, 7, 100), - "allocator is terminating the process instead of returning 0"); + "invalid-allocation-alignment"); EXPECT_EQ(0L, p); } +#endif + TEST(Mman, PosixMemalign) { ThreadState *thr = cur_thread(); @@ -197,16 +184,6 @@ EXPECT_NE(p, (void*)0); EXPECT_EQ(res, 0); user_free(thr, 0, p); - - p = NULL; - // Alignment is not a power of two, although is a multiple of sizeof(void*). - EXPECT_DEATH(res = user_posix_memalign(thr, 0, &p, 3 * sizeof(p), 100), - "allocator is terminating the process instead of returning 0"); - EXPECT_EQ(0L, p); - // Alignment is not a multiple of sizeof(void*), although is a power of 2. - EXPECT_DEATH(res = user_posix_memalign(thr, 0, &p, 2, 100), - "allocator is terminating the process instead of returning 0"); - EXPECT_EQ(0L, p); } TEST(Mman, AlignedAlloc) { @@ -215,18 +192,6 @@ void *p = user_aligned_alloc(thr, 0, 8, 64); EXPECT_NE(p, (void*)0); user_free(thr, 0, p); - - p = NULL; - // Alignement is not a power of 2. - EXPECT_DEATH(p = user_aligned_alloc(thr, 0, 7, 100), - "allocator is terminating the process instead of returning 0"); - EXPECT_EQ(0L, p); - // Size is not a multiple of alignment. - EXPECT_DEATH(p = user_aligned_alloc(thr, 0, 8, 100), - "allocator is terminating the process instead of returning 0"); - EXPECT_EQ(0L, p); } -#endif - } // namespace __tsan Index: test/sanitizer_common/TestCases/Linux/aligned_alloc-alignment.cc =================================================================== --- test/sanitizer_common/TestCases/Linux/aligned_alloc-alignment.cc +++ test/sanitizer_common/TestCases/Linux/aligned_alloc-alignment.cc @@ -1,14 +1,23 @@ // RUN: %clangxx %collect_stack_traces -O0 %s -o %t + +// Alignment is not a power of 2: // RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 17 2>&1 | FileCheck %s +// Size is not a multiple of alignment: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 8 2>&1 | FileCheck %s +// Alignment is 0: // RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 0 2>&1 | FileCheck %s + +// The same for allocator_may_return_null=1: // RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 17 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-NULL // RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL // REQUIRES: stable-runtime -// UNSUPPORTED: android, tsan, ubsan +// UNSUPPORTED: android, ubsan #include +#include #include #include @@ -21,12 +30,14 @@ void *p = aligned_alloc(alignment, 100); // CHECK: {{ERROR: .*Sanitizer: invalid alignment requested in aligned_alloc}} // Handle a case when aligned_alloc is aliased by memalign. - // CHECK: {{#0 0x.* in .*}}{{aligned_alloc|memalign}} - // CHECK: {{#1 0x.* in main .*aligned_alloc-alignment.cc:}}[[@LINE-4]] + // CHECK: {{#0 .*}}{{aligned_alloc|memalign}} + // CHECK: {{#1 .*main .*aligned_alloc-alignment.cc:}}[[@LINE-4]] // CHECK: {{SUMMARY: .*Sanitizer: invalid-aligned-alloc-alignment}} - printf("pointer after failed aligned_alloc: %zd\n", (size_t)p); - // CHECK-NULL: pointer after failed aligned_alloc: 0 + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "errno: %d, p: %lx\n", errno, (long)p); + // CHECK-NULL: errno: 22, p: 0 return 0; } Index: test/sanitizer_common/TestCases/Linux/pvalloc-overflow.cc =================================================================== --- test/sanitizer_common/TestCases/Linux/pvalloc-overflow.cc +++ test/sanitizer_common/TestCases/Linux/pvalloc-overflow.cc @@ -6,7 +6,7 @@ // REQUIRES: stable-runtime -// UNSUPPORTED: android, freebsd, netbsd, tsan, ubsan +// UNSUPPORTED: android, freebsd, netbsd, ubsan // Checks that pvalloc overflows are caught. If the allocator is allowed to // return null, the errno should be set to ENOMEM. @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -32,15 +33,15 @@ } else { assert(0); } + // CHECK: {{ERROR: .*Sanitizer: pvalloc parameters overflow: size .* rounded up to system page size .* cannot be represented in type size_t}} + // CHECK: {{#0 .*pvalloc}} + // CHECK: {{#1 .*main .*pvalloc-overflow.cc:}} + // CHECK: {{SUMMARY: .*Sanitizer: pvalloc-overflow}} + + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "errno: %d, p: %lx\n", errno, (long)p); + // CHECK-NULL: errno: 12, p: 0 - fprintf(stderr, "errno: %d\n", errno); - - return p != nullptr; + return 0; } - -// CHECK: {{ERROR: .*Sanitizer: 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: .*Sanitizer: pvalloc-overflow}} - -// CHECK-NULL: errno: 12 Index: test/sanitizer_common/TestCases/Posix/posix_memalign-alignment.cc =================================================================== --- test/sanitizer_common/TestCases/Posix/posix_memalign-alignment.cc +++ test/sanitizer_common/TestCases/Posix/posix_memalign-alignment.cc @@ -1,14 +1,26 @@ // RUN: %clangxx %collect_stack_traces -O0 %s -o %t + +// Alignment is not a power of two: // RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 17 2>&1 | FileCheck %s +// Alignment is not a power of two, although is a multiple of sizeof(void*): +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 24 2>&1 | FileCheck %s +// Alignment is not a multiple of sizeof(void*), although is a power of 2: +// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 2 2>&1 | FileCheck %s +// Alignment is 0: // RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t 0 2>&1 | FileCheck %s + +// The same for allocator_may_return_null=1: // RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 17 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 24 2>&1 | FileCheck %s --check-prefix=CHECK-NULL +// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-NULL // RUN: %env_tool_opts=allocator_may_return_null=1 %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL // REQUIRES: stable-runtime -// UNSUPPORTED: tsan, ubsan +// UNSUPPORTED: ubsan #include +#include #include #include @@ -16,16 +28,20 @@ assert(argc == 2); const int alignment = atoi(argv[1]); - void *p = reinterpret_cast(42); + void* const kInitialPtrValue = reinterpret_cast(0x2a); + void *p = kInitialPtrValue; + errno = 0; int res = posix_memalign(&p, alignment, 100); // CHECK: {{ERROR: .*Sanitizer: invalid alignment requested in posix_memalign}} - // CHECK: {{#0 0x.* in .*posix_memalign}} - // CHECK: {{#1 0x.* in main .*posix_memalign-alignment.cc:}}[[@LINE-3]] + // CHECK: {{#0 .*posix_memalign}} + // CHECK: {{#1 .*main .*posix_memalign-alignment.cc:}}[[@LINE-3]] // CHECK: {{SUMMARY: .*Sanitizer: invalid-posix-memalign-alignment}} - printf("pointer after failed posix_memalign: %zd\n", (size_t)p); - // CHECK-NULL: pointer after failed posix_memalign: 42 + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "errno: %d, res: %d, p: %lx\n", errno, res, (long)p); + // CHECK-NULL: errno: 0, res: 22, p: 2a return 0; } Index: test/sanitizer_common/TestCases/allocator_returns_null.cc =================================================================== --- test/sanitizer_common/TestCases/allocator_returns_null.cc +++ test/sanitizer_common/TestCases/allocator_returns_null.cc @@ -1,8 +1,8 @@ // Test the behavior of malloc/calloc/realloc/new when the allocation size // exceeds the sanitizer's allocator 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 and set errno to -// the appropriate error code. +// allocator_may_return_null=1 the allocator should return nullptr and set errno +// to the appropriate error code. // // RUN: %clangxx -O0 %s -o %t // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH @@ -36,7 +36,7 @@ // RUN: | FileCheck %s --check-prefix=CHECK-NULL // TODO(alekseyshl): win32 is disabled due to failing errno tests, fix it there. -// UNSUPPORTED: tsan, ubsan, win32 +// UNSUPPORTED: ubsan, win32 #include #include @@ -51,12 +51,8 @@ const char *action = argv[1]; fprintf(stderr, "%s:\n", action); - // The maximum value of all supported sanitizers: - // ASan: asan_allocator.cc, search for kMaxAllowedMallocSize. - // LSan: lsan_allocator.cc, search for kMaxAllowedMallocSize. - // ASan + LSan: ASan limit is used. - // MSan: msan_allocator.cc, search for kMaxAllowedMallocSize. - // TSan: tsan_mman.cc, user_alloc_internal function. + // The maximum value of all supported sanitizers (search for + // kMaxAllowedMallocSize). For ASan + LSan, ASan limit is used. static const size_t kMaxAllowedMallocSizePlusOne = #if __LP64__ || defined(_WIN64) (1ULL << 40) + 1; @@ -90,11 +86,11 @@ assert(0); } - fprintf(stderr, "errno: %d\n", errno); + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "errno: %d, x: %lx\n", errno, (long)x); - free(x); - - return x != nullptr; + return 0; } // CHECK-mCRASH: malloc: @@ -115,4 +111,4 @@ // CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow}} -// CHECK-NULL: errno: 12 +// CHECK-NULL: errno: 12, x: 0 Index: test/tsan/allocator_returns_null.cc =================================================================== --- test/tsan/allocator_returns_null.cc +++ test/tsan/allocator_returns_null.cc @@ -1,124 +0,0 @@ -// 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, 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 \ -// 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 -#include -#include -#include -#include -#include -#include - -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); - - // The limit enforced in tsan_mman.cc, user_alloc_internal function. - 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::max(); - size_t kArraySize = 4096; - volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - 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 = 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, "errno: %d\n", errno); - - // 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: -// CHECK-cCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: ThreadSanitizer's allocator is terminating the process -// CHECK-rCRASH: realloc: -// 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: errno: 12 -// CHECK-mNULL: x: 0 -// CHECK-cNULL: calloc: -// CHECK-cNULL: errno: 12 -// CHECK-cNULL: x: 0 -// CHECK-coNULL: calloc-overflow: -// CHECK-coNULL: errno: 12 -// CHECK-coNULL: x: 0 -// CHECK-rNULL: realloc: -// CHECK-rNULL: errno: 12 -// CHECK-rNULL: x: 0 -// CHECK-mrNULL: realloc-after-malloc: -// CHECK-mrNULL: errno: 12 -// CHECK-mrNULL: x: 0 -// CHECK-nnNULL: new-nothrow: -// CHECK-nnNULL: x: 0