https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/77168
>From a127373cf1ac1676ce17ce8dca909d0c3bce9d18 Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalyb...@google.com> Date: Mon, 8 Jan 2024 11:45:37 -0800 Subject: [PATCH 1/2] [NFC][msan] Switch allocator interface to use BufferedStackTrace We will need it to unwind for fatal errors. Pull Request: https://github.com/llvm/llvm-project/pull/77363 --- compiler-rt/lib/msan/msan.h | 23 ++++++++++---------- compiler-rt/lib/msan/msan_allocator.cpp | 29 +++++++++++++------------ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h index 25fa2212bdadd3..753e6b260734f9 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -255,18 +255,19 @@ char *GetProcSelfMaps(); void InitializeInterceptors(); void MsanAllocatorInit(); -void MsanDeallocate(StackTrace *stack, void *ptr); - -void *msan_malloc(uptr size, StackTrace *stack); -void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack); -void *msan_realloc(void *ptr, uptr size, StackTrace *stack); -void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack); -void *msan_valloc(uptr size, StackTrace *stack); -void *msan_pvalloc(uptr size, StackTrace *stack); -void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack); -void *msan_memalign(uptr alignment, uptr size, StackTrace *stack); +void MsanDeallocate(BufferedStackTrace *stack, void *ptr); + +void *msan_malloc(uptr size, BufferedStackTrace *stack); +void *msan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); +void *msan_realloc(void *ptr, uptr size, BufferedStackTrace *stack); +void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, + BufferedStackTrace *stack); +void *msan_valloc(uptr size, BufferedStackTrace *stack); +void *msan_pvalloc(uptr size, BufferedStackTrace *stack); +void *msan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack); +void *msan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack); int msan_posix_memalign(void **memptr, uptr alignment, uptr size, - StackTrace *stack); + BufferedStackTrace *stack); void InstallTrapHandler(); void InstallAtExitHandler(); diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp index 72a7f980d39fb0..987c894c79d45e 100644 --- a/compiler-rt/lib/msan/msan_allocator.cpp +++ b/compiler-rt/lib/msan/msan_allocator.cpp @@ -178,7 +178,7 @@ void MsanThreadLocalMallocStorage::CommitBack() { allocator.DestroyCache(GetAllocatorCache(this)); } -static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, +static void *MsanAllocate(BufferedStackTrace *stack, uptr size, uptr alignment, bool zeroise) { if (size > max_malloc_size) { if (AllocatorMayReturnNull()) { @@ -229,7 +229,7 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, return allocated; } -void MsanDeallocate(StackTrace *stack, void *p) { +void MsanDeallocate(BufferedStackTrace *stack, void *p) { CHECK(p); UnpoisonParam(1); RunFreeHooks(p); @@ -259,8 +259,8 @@ void MsanDeallocate(StackTrace *stack, void *p) { } } -static void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, - uptr alignment) { +static void *MsanReallocate(BufferedStackTrace *stack, void *old_p, + uptr new_size, uptr alignment) { Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p)); uptr old_size = meta->requested_size; uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p); @@ -284,7 +284,7 @@ static void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, return new_p; } -static void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { +static void *MsanCalloc(BufferedStackTrace *stack, uptr nmemb, uptr size) { if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { if (AllocatorMayReturnNull()) return nullptr; @@ -320,15 +320,15 @@ static uptr AllocationSizeFast(const void *p) { return reinterpret_cast<Metadata *>(allocator.GetMetaData(p))->requested_size; } -void *msan_malloc(uptr size, StackTrace *stack) { +void *msan_malloc(uptr size, BufferedStackTrace *stack) { return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); } -void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack) { +void *msan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { return SetErrnoOnNull(MsanCalloc(stack, nmemb, size)); } -void *msan_realloc(void *ptr, uptr size, StackTrace *stack) { +void *msan_realloc(void *ptr, uptr size, BufferedStackTrace *stack) { if (!ptr) return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); if (size == 0) { @@ -338,7 +338,8 @@ void *msan_realloc(void *ptr, uptr size, StackTrace *stack) { return SetErrnoOnNull(MsanReallocate(stack, ptr, size, sizeof(u64))); } -void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) { +void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, + BufferedStackTrace *stack) { if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { errno = errno_ENOMEM; if (AllocatorMayReturnNull()) @@ -348,11 +349,11 @@ void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) { return msan_realloc(ptr, nmemb * size, stack); } -void *msan_valloc(uptr size, StackTrace *stack) { +void *msan_valloc(uptr size, BufferedStackTrace *stack) { return SetErrnoOnNull(MsanAllocate(stack, size, GetPageSizeCached(), false)); } -void *msan_pvalloc(uptr size, StackTrace *stack) { +void *msan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { errno = errno_ENOMEM; @@ -365,7 +366,7 @@ void *msan_pvalloc(uptr size, StackTrace *stack) { return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); } -void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) { +void *msan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { errno = errno_EINVAL; if (AllocatorMayReturnNull()) @@ -375,7 +376,7 @@ void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) { return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); } -void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) { +void *msan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; if (AllocatorMayReturnNull()) @@ -386,7 +387,7 @@ void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) { } int msan_posix_memalign(void **memptr, uptr alignment, uptr size, - StackTrace *stack) { + BufferedStackTrace *stack) { if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { if (AllocatorMayReturnNull()) return errno_EINVAL; >From 1de5a3d46d64d9ca8c051f11afa98f80e99064f2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalyb...@google.com> Date: Fri, 5 Jan 2024 18:15:58 -0800 Subject: [PATCH 2/2] [msan] Unwind stack before fatal reports Msan does not unwind stack in malloc without origins, but we still need trace for fatal errors. Pull Request: https://github.com/llvm/llvm-project/pull/77168 --- compiler-rt/lib/msan/msan.h | 11 ++++++++ compiler-rt/lib/msan/msan_allocator.cpp | 11 +++++++- compiler-rt/lib/msan/msan_new_delete.cpp | 26 ++++++++++++------- .../TestCases/max_allocation_size.cpp | 10 ++++++- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h index 753e6b260734f9..c3e45b38db2a13 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -322,6 +322,17 @@ const int STACK_TRACE_TAG_VPTR = STACK_TRACE_TAG_FIELDS + 1; stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal); \ } +#define GET_FATAL_STACK_TRACE \ + GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) + +// Unwind the stack for fatal error, as the parameter `stack` is +// empty without origins. +#define GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(STACK) \ + if (msan_inited && (STACK)->size == 0) { \ + (STACK)->Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, \ + common_flags()->fast_unwind_on_fatal); \ + } + class ScopedThreadLocalStateBackup { public: ScopedThreadLocalStateBackup() { Backup(); } diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp index 987c894c79d45e..847e0e26f0504b 100644 --- a/compiler-rt/lib/msan/msan_allocator.cpp +++ b/compiler-rt/lib/msan/msan_allocator.cpp @@ -180,16 +180,18 @@ void MsanThreadLocalMallocStorage::CommitBack() { static void *MsanAllocate(BufferedStackTrace *stack, uptr size, uptr alignment, bool zeroise) { - if (size > max_malloc_size) { + if (UNLIKELY(size > max_malloc_size)) { if (AllocatorMayReturnNull()) { Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size); return nullptr; } + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportAllocationSizeTooBig(size, max_malloc_size, stack); } if (UNLIKELY(IsRssLimitExceeded())) { if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportRssLimitExceeded(stack); } MsanThread *t = GetCurrentThread(); @@ -206,6 +208,7 @@ static void *MsanAllocate(BufferedStackTrace *stack, uptr size, uptr alignment, SetAllocatorOutOfMemory(); if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportOutOfMemory(size, stack); } Metadata *meta = @@ -288,6 +291,7 @@ static void *MsanCalloc(BufferedStackTrace *stack, uptr nmemb, uptr size) { if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportCallocOverflow(nmemb, size, stack); } return MsanAllocate(stack, nmemb * size, sizeof(u64), true); @@ -344,6 +348,7 @@ void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, errno = errno_ENOMEM; if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportReallocArrayOverflow(nmemb, size, stack); } return msan_realloc(ptr, nmemb * size, stack); @@ -359,6 +364,7 @@ void *msan_pvalloc(uptr size, BufferedStackTrace *stack) { errno = errno_ENOMEM; if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportPvallocOverflow(size, stack); } // pvalloc(0) should allocate one page. @@ -371,6 +377,7 @@ void *msan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { errno = errno_EINVAL; if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportInvalidAlignedAllocAlignment(size, alignment, stack); } return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); @@ -381,6 +388,7 @@ void *msan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack) { errno = errno_EINVAL; if (AllocatorMayReturnNull()) return nullptr; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportInvalidAllocationAlignment(alignment, stack); } return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); @@ -391,6 +399,7 @@ int msan_posix_memalign(void **memptr, uptr alignment, uptr size, if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { if (AllocatorMayReturnNull()) return errno_EINVAL; + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack); ReportInvalidPosixMemalignAlignment(alignment, stack); } void *ptr = MsanAllocate(stack, size, alignment, false); diff --git a/compiler-rt/lib/msan/msan_new_delete.cpp b/compiler-rt/lib/msan/msan_new_delete.cpp index d4e95c0f65137d..fe6399f5910737 100644 --- a/compiler-rt/lib/msan/msan_new_delete.cpp +++ b/compiler-rt/lib/msan/msan_new_delete.cpp @@ -30,16 +30,22 @@ namespace std { // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. -#define OPERATOR_NEW_BODY(nothrow) \ - GET_MALLOC_STACK_TRACE; \ - void *res = msan_malloc(size, &stack);\ - 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)) ReportOutOfMemory(size, &stack);\ - return res; +# define OPERATOR_NEW_BODY(nothrow) \ + GET_MALLOC_STACK_TRACE; \ + void *res = msan_malloc(size, &stack); \ + if (!nothrow && UNLIKELY(!res)) { \ + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(&stack); \ + 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)) { \ + GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(&stack); \ + ReportOutOfMemory(size, &stack); \ + } \ + return res; INTERCEPTOR_ATTRIBUTE void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } diff --git a/compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp b/compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp index ace28965f3c1ba..c74f241c32b754 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp @@ -35,7 +35,7 @@ // RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \ // RUN: %run %t new-nothrow 2>&1 | FileCheck %s --check-prefix=CHECK-NULL -// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \ +// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0:fast_unwind_on_malloc=0 \ // RUN: not %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-sCRASH // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \ // RUN: %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-NULL @@ -123,20 +123,28 @@ int main(int Argc, char **Argv) { } // CHECK-mCRASH: malloc: +// CHECK-mCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-cCRASH: calloc: +// CHECK-cCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-rCRASH: realloc: +// CHECK-rCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-mrCRASH: realloc-after-malloc: +// CHECK-mrCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-nCRASH: new: +// CHECK-nCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-nCRASH-OOM: new: +// CHECK-nCRASH-OOM: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory}} // CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-sCRASH: strndup: +// CHECK-sCRASH: #{{[0-9]+.*}}max_allocation_size.cpp // CHECK-sCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}} // CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow|strndup}} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits