Index: lib/msan/msan.h =================================================================== --- lib/msan/msan.h +++ lib/msan/msan.h @@ -316,14 +316,6 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp, void *context, bool request_fast_unwind); -void ReportUMR(StackTrace *stack, u32 origin); -void ReportExpectedUMRNotFound(StackTrace *stack); -void ReportStats(); -void ReportAtExitStatistics(); -void DescribeMemoryRange(const void *x, uptr size); -void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, - uptr offset); - // Unpoison first n function arguments. void UnpoisonParam(uptr n); void UnpoisonThreadLocalState(); Index: lib/msan/msan.cc =================================================================== --- lib/msan/msan.cc +++ lib/msan/msan.cc @@ -15,6 +15,7 @@ #include "msan.h" #include "msan_chained_origin_depot.h" #include "msan_origin.h" +#include "msan_report.h" #include "msan_thread.h" #include "msan_poisoning.h" #include "sanitizer_common/sanitizer_atomic.h" Index: lib/msan/msan_allocator.cc =================================================================== --- lib/msan/msan_allocator.cc +++ lib/msan/msan_allocator.cc @@ -15,6 +15,7 @@ #include "sanitizer_common/sanitizer_allocator.h" #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_errno.h" #include "msan.h" #include "msan_allocator.h" @@ -139,9 +140,11 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, bool zeroise) { if (size > kMaxAllowedMallocSize) { - Report("WARNING: MemorySanitizer failed to allocate %p bytes\n", - (void *)size); - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (AllocatorMayReturnNull()) { + Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size); + return nullptr; + } + ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack); } MsanThread *t = GetCurrentThread(); void *allocated; @@ -153,8 +156,12 @@ AllocatorCache *cache = &fallback_allocator_cache; allocated = allocator.Allocate(cache, size, alignment); } - if (UNLIKELY(!allocated)) - return ReturnNullOrDieOnFailure::OnOOM(); + if (UNLIKELY(!allocated)) { + SetAllocatorOutOfMemory(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportOutOfMemory(size, stack); + } Metadata *meta = reinterpret_cast(allocator.GetMetaData(allocated)); meta->requested_size = size; @@ -224,6 +231,15 @@ return new_p; } +void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { + if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportCallocOverflow(nmemb, size, stack); + } + return MsanAllocate(stack, nmemb * size, sizeof(u64), true); +} + static uptr AllocationSize(const void *p) { if (!p) return 0; const void *beg = allocator.GetBlockBegin(p); @@ -237,9 +253,7 @@ } void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack) { - if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) - return SetErrnoOnNull(ReturnNullOrDieOnFailure::OnBadRequest()); - return SetErrnoOnNull(MsanAllocate(stack, nmemb * size, sizeof(u64), true)); + return SetErrnoOnNull(MsanCalloc(stack, nmemb, size)); } void *msan_realloc(void *ptr, uptr size, StackTrace *stack) { @@ -260,7 +274,9 @@ 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; @@ -270,7 +286,9 @@ void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) { if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { errno = errno_EINVAL; - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAlignedAllocAlignment(size, alignment, stack); } return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); } @@ -278,7 +296,9 @@ void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; - return ReturnNullOrDieOnFailure::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAllocationAlignment(alignment, stack); } return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); } @@ -286,11 +306,13 @@ int msan_posix_memalign(void **memptr, uptr alignment, uptr size, StackTrace *stack) { if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { - ReturnNullOrDieOnFailure::OnBadRequest(); - return errno_EINVAL; + if (AllocatorMayReturnNull()) + return errno_EINVAL; + ReportInvalidPosixMemalignAlignment(alignment, stack); } void *ptr = MsanAllocate(stack, size, alignment, false); if (UNLIKELY(!ptr)) + // OOM error is already taken care of by MsanAllocate. return errno_ENOMEM; CHECK(IsAligned((uptr)ptr, alignment)); *memptr = ptr; Index: lib/msan/msan_interceptors.cc =================================================================== --- lib/msan/msan_interceptors.cc +++ lib/msan/msan_interceptors.cc @@ -19,6 +19,7 @@ #include "msan.h" #include "msan_chained_origin_depot.h" #include "msan_origin.h" +#include "msan_report.h" #include "msan_thread.h" #include "msan_poisoning.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" Index: lib/msan/msan_linux.cc =================================================================== --- lib/msan/msan_linux.cc +++ lib/msan/msan_linux.cc @@ -16,6 +16,7 @@ #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "msan.h" +#include "msan_report.h" #include "msan_thread.h" #include Index: lib/msan/msan_new_delete.cc =================================================================== --- lib/msan/msan_new_delete.cc +++ lib/msan/msan_new_delete.cc @@ -15,6 +15,7 @@ #include "msan.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h" #if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE @@ -33,12 +34,12 @@ #define OPERATOR_NEW_BODY(nothrow) \ GET_MALLOC_STACK_TRACE; \ void *res = msan_malloc(size, &stack);\ - if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ return res #define OPERATOR_NEW_BODY_ALIGN(nothrow) \ GET_MALLOC_STACK_TRACE;\ void *res = msan_memalign((uptr)align, size, &stack);\ - if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ return res; INTERCEPTOR_ATTRIBUTE Index: lib/msan/msan_report.h =================================================================== --- /dev/null +++ lib/msan/msan_report.h @@ -0,0 +1,34 @@ +//===-- msan_report.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of MemorySanitizer. MSan-private header for error +/// reporting functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef MSAN_REPORT_H +#define MSAN_REPORT_H + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_stacktrace.h" + +namespace __msan { + +void ReportUMR(StackTrace *stack, u32 origin); +void ReportExpectedUMRNotFound(StackTrace *stack); +void ReportStats(); +void ReportAtExitStatistics(); +void DescribeMemoryRange(const void *x, uptr size); +void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, + uptr offset); + +} // namespace __msan + +#endif // MSAN_REPORT_H Index: lib/msan/msan_report.cc =================================================================== --- lib/msan/msan_report.cc +++ lib/msan/msan_report.cc @@ -15,6 +15,7 @@ #include "msan.h" #include "msan_chained_origin_depot.h" #include "msan_origin.h" +#include "msan_report.h" #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" @@ -30,8 +31,8 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() { } - const char *Origin() { return Magenta(); } - const char *Name() { return Green(); } + const char *Origin() const { return Magenta(); } + const char *Name() const { return Green(); } }; static void DescribeStackOrigin(const char *so, uptr pc) { Index: test/msan/Linux/aligned_alloc-alignment.cc =================================================================== --- /dev/null +++ test/msan/Linux/aligned_alloc-alignment.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 -g %s -o %t +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// UNSUPPORTED: android + +// REQUIRES: stable-runtime + +#include +#include + +extern void *aligned_alloc(size_t alignment, size_t size); + +int main() { + void *p = aligned_alloc(17, 100); + // CHECK: ERROR: MemorySanitizer: invalid alignment requested in aligned_alloc: 17 + // Check just the top frame since mips is forced to use store_context_size==1 + // and also handle a case when aligned_alloc is aliased by memalign. + // CHECK: {{#0 0x.* in .*}}{{aligned_alloc|memalign}} + // CHECK: SUMMARY: MemorySanitizer: invalid-aligned-alloc-alignment + + printf("pointer after failed aligned_alloc: %zd\n", (size_t)p); + // CHECK-NULL: pointer after failed aligned_alloc: 0 + + return 0; +} Index: test/msan/Posix/lit.local.cfg =================================================================== --- /dev/null +++ test/msan/Posix/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os in ['Windows']: + config.unsupported = True Index: test/msan/Posix/posix_memalign-alignment.cc =================================================================== --- /dev/null +++ test/msan/Posix/posix_memalign-alignment.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 -g %s -o %t +// RUN: MSAN_OPTIONS=$MSAN_OPTIONS:allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s +// RUN: MSAN_OPTIONS=$MSAN_OPTIONS:allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL + +// REQUIRES: stable-runtime + +#include +#include + +int main() { + void *p = reinterpret_cast(42); + int res = posix_memalign(&p, 17, 100); + // CHECK: ERROR: MemorySanitizer: invalid alignment requested in posix_memalign: 17 + // Check just the top frame since mips is forced to use store_context_size==1 + // CHECK: {{#0 0x.* in .*posix_memalign}} + // CHECK: SUMMARY: MemorySanitizer: 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; +} Index: test/msan/allocator_returns_null.cc =================================================================== --- test/msan/allocator_returns_null.cc +++ test/msan/allocator_returns_null.cc @@ -30,7 +30,7 @@ // 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: | FileCheck %s --check-prefix=CHECK-nCRASH-OOM // 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 \ @@ -98,19 +98,21 @@ } // CHECK-mCRASH: malloc: -// CHECK-mCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-mCRASH: SUMMARY: MemorySanitizer: allocation-size-too-big // CHECK-cCRASH: calloc: -// CHECK-cCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-cCRASH: SUMMARY: MemorySanitizer: allocation-size-too-big // CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-coCRASH: SUMMARY: MemorySanitizer: calloc-overflow // CHECK-rCRASH: realloc: -// CHECK-rCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-rCRASH: SUMMARY: MemorySanitizer: allocation-size-too-big // CHECK-mrCRASH: realloc-after-malloc: -// CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-mrCRASH: SUMMARY: MemorySanitizer: allocation-size-too-big // CHECK-nCRASH: new: -// CHECK-nCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-nCRASH: SUMMARY: MemorySanitizer: allocation-size-too-big +// CHECK-nCRASH-OOM: new: +// CHECK-nCRASH-OOM: SUMMARY: MemorySanitizer: out-of-memory // CHECK-nnCRASH: new-nothrow: -// CHECK-nnCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-nnCRASH: SUMMARY: MemorySanitizer: allocation-size-too-big // CHECK-mNULL: malloc: // CHECK-mNULL: errno: 12 Index: test/msan/pvalloc.cc =================================================================== --- test/msan/pvalloc.cc +++ test/msan/pvalloc.cc @@ -41,4 +41,5 @@ return 0; } -// CHECK: MemorySanitizer's allocator is terminating the process +// CHECK: {{ERROR: MemorySanitizer: pvalloc parameters overflow: size .* rounded up to system page size .* cannot be represented in type size_t}} +// CHECK: SUMMARY: MemorySanitizer: pvalloc-overflow