[libcxx] [flang] [lldb] [lld] [clang] [libc] [clang-tools-extra] [compiler-rt] [llvm] [msan] Unwind stack before fatal reports (PR #77168)

Vitaly Buka via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 8 11:49:27 PST 2024


https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/77168

>From d4953b7a14dfb1d351b543e2546d710ae30173ed Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Fri, 5 Jan 2024 18:42:43 -0800
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 compiler-rt/lib/msan/msan.h                   |  3 ++
 compiler-rt/lib/msan/msan_allocator.cpp       | 29 ++++++++++++-------
 compiler-rt/lib/msan/msan_new_delete.cpp      | 26 ++++++++++-------
 .../TestCases/max_allocation_size.cpp         | 10 ++++++-
 4 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h
index 25fa2212bdadd3..b717161577a1db 100644
--- a/compiler-rt/lib/msan/msan.h
+++ b/compiler-rt/lib/msan/msan.h
@@ -321,6 +321,9 @@ 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())
+
 class ScopedThreadLocalStateBackup {
  public:
   ScopedThreadLocalStateBackup() { Backup(); }
diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp
index 72a7f980d39fb0..f71f59cedf820e 100644
--- a/compiler-rt/lib/msan/msan_allocator.cpp
+++ b/compiler-rt/lib/msan/msan_allocator.cpp
@@ -180,17 +180,19 @@ void MsanThreadLocalMallocStorage::CommitBack() {
 
 static void *MsanAllocate(StackTrace *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;
     }
-    ReportAllocationSizeTooBig(size, max_malloc_size, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportAllocationSizeTooBig(size, max_malloc_size, &stack);
   }
   if (UNLIKELY(IsRssLimitExceeded())) {
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportRssLimitExceeded(stack);
+    GET_FATAL_STACK_TRACE;
+    ReportRssLimitExceeded(&stack);
   }
   MsanThread *t = GetCurrentThread();
   void *allocated;
@@ -206,7 +208,8 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
     SetAllocatorOutOfMemory();
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportOutOfMemory(size, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportOutOfMemory(size, &stack);
   }
   Metadata *meta =
       reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
@@ -288,7 +291,8 @@ static void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportCallocOverflow(nmemb, size, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportCallocOverflow(nmemb, size, &stack);
   }
   return MsanAllocate(stack, nmemb * size, sizeof(u64), true);
 }
@@ -343,7 +347,8 @@ void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) {
     errno = errno_ENOMEM;
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportReallocArrayOverflow(nmemb, size, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportReallocArrayOverflow(nmemb, size, &stack);
   }
   return msan_realloc(ptr, nmemb * size, stack);
 }
@@ -358,7 +363,8 @@ void *msan_pvalloc(uptr size, StackTrace *stack) {
     errno = errno_ENOMEM;
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportPvallocOverflow(size, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportPvallocOverflow(size, &stack);
   }
   // pvalloc(0) should allocate one page.
   size = size ? RoundUpTo(size, PageSize) : PageSize;
@@ -370,7 +376,8 @@ void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
     errno = errno_EINVAL;
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportInvalidAlignedAllocAlignment(size, alignment, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportInvalidAlignedAllocAlignment(size, alignment, &stack);
   }
   return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
 }
@@ -380,7 +387,8 @@ void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) {
     errno = errno_EINVAL;
     if (AllocatorMayReturnNull())
       return nullptr;
-    ReportInvalidAllocationAlignment(alignment, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportInvalidAllocationAlignment(alignment, &stack);
   }
   return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
 }
@@ -390,7 +398,8 @@ int msan_posix_memalign(void **memptr, uptr alignment, uptr size,
   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
     if (AllocatorMayReturnNull())
       return errno_EINVAL;
-    ReportInvalidPosixMemalignAlignment(alignment, stack);
+    GET_FATAL_STACK_TRACE;
+    ReportInvalidPosixMemalignAlignment(alignment, &stack);
   }
   void *ptr = MsanAllocate(stack, size, alignment, false);
   if (UNLIKELY(!ptr))
diff --git a/compiler-rt/lib/msan/msan_new_delete.cpp b/compiler-rt/lib/msan/msan_new_delete.cpp
index d4e95c0f65137d..3329a05cca2a86 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;               \
+      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;                              \
+      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}}

>From 6496ace3246f993e711cc6ab757d2d8c4e4f16f0 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 8 Jan 2024 11:26:10 -0800
Subject: [PATCH 2/2] comment

Created using spr 1.3.4
---
 compiler-rt/lib/msan/msan_allocator.cpp  | 24 ++++++++++++--------
 compiler-rt/lib/msan/msan_new_delete.cpp | 28 ++++++++++++------------
 2 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp
index f71f59cedf820e..bd05799b0b6fda 100644
--- a/compiler-rt/lib/msan/msan_allocator.cpp
+++ b/compiler-rt/lib/msan/msan_allocator.cpp
@@ -178,6 +178,10 @@ void MsanThreadLocalMallocStorage::CommitBack() {
   allocator.DestroyCache(GetAllocatorCache(this));
 }
 
+// Unwind the stack for fatal error, as the parameter `stack` is
+// empty without origins.
+#define GET_FATAL_STACK_TRACE MSAN_GET_FATAL_STACK_TRACE_AGAIN
+
 static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
                           bool zeroise) {
   if (UNLIKELY(size > max_malloc_size)) {
@@ -185,13 +189,13 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
       Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size);
       return nullptr;
     }
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportAllocationSizeTooBig(size, max_malloc_size, &stack);
   }
   if (UNLIKELY(IsRssLimitExceeded())) {
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportRssLimitExceeded(&stack);
   }
   MsanThread *t = GetCurrentThread();
@@ -208,7 +212,7 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
     SetAllocatorOutOfMemory();
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportOutOfMemory(size, &stack);
   }
   Metadata *meta =
@@ -291,7 +295,7 @@ static void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportCallocOverflow(nmemb, size, &stack);
   }
   return MsanAllocate(stack, nmemb * size, sizeof(u64), true);
@@ -347,7 +351,7 @@ void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) {
     errno = errno_ENOMEM;
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportReallocArrayOverflow(nmemb, size, &stack);
   }
   return msan_realloc(ptr, nmemb * size, stack);
@@ -363,7 +367,7 @@ void *msan_pvalloc(uptr size, StackTrace *stack) {
     errno = errno_ENOMEM;
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportPvallocOverflow(size, &stack);
   }
   // pvalloc(0) should allocate one page.
@@ -376,7 +380,7 @@ void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
     errno = errno_EINVAL;
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportInvalidAlignedAllocAlignment(size, alignment, &stack);
   }
   return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
@@ -387,7 +391,7 @@ void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) {
     errno = errno_EINVAL;
     if (AllocatorMayReturnNull())
       return nullptr;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportInvalidAllocationAlignment(alignment, &stack);
   }
   return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
@@ -398,7 +402,7 @@ int msan_posix_memalign(void **memptr, uptr alignment, uptr size,
   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
     if (AllocatorMayReturnNull())
       return errno_EINVAL;
-    GET_FATAL_STACK_TRACE;
+    MSAN_GET_FATAL_STACK_TRACE_AGAIN;
     ReportInvalidPosixMemalignAlignment(alignment, &stack);
   }
   void *ptr = MsanAllocate(stack, size, alignment, false);
@@ -410,6 +414,8 @@ int msan_posix_memalign(void **memptr, uptr alignment, uptr size,
   return 0;
 }
 
+#undef MSAN_GET_FATAL_STACK_TRACE_AGAIN
+
 } // namespace __msan
 
 using namespace __msan;
diff --git a/compiler-rt/lib/msan/msan_new_delete.cpp b/compiler-rt/lib/msan/msan_new_delete.cpp
index 3329a05cca2a86..9f5a4b2d38b256 100644
--- a/compiler-rt/lib/msan/msan_new_delete.cpp
+++ b/compiler-rt/lib/msan/msan_new_delete.cpp
@@ -30,21 +30,21 @@ 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)) {      \
-      GET_FATAL_STACK_TRACE;               \
-      ReportOutOfMemory(size, &stack);     \
-    }                                      \
+#  define OPERATOR_NEW_BODY(nothrow)                                      \
+    GET_MALLOC_STACK_TRACE;                                               \
+    void *res = msan_malloc(size, &stack);                                \
+    if (!nothrow && UNLIKELY(!res)) {                                     \
+      GET_FATAL_STACK_TRACE; /* see `MSAN_GET_FATAL_STACK_TRACE_AGAIN` */ \
+      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;                              \
-      ReportOutOfMemory(size, &stack);                    \
-    }                                                     \
+#  define OPERATOR_NEW_BODY_ALIGN(nothrow)                               \
+    GET_MALLOC_STACK_TRACE; /* see `MSAN_GET_FATAL_STACK_TRACE_AGAIN` */ \
+    void *res = msan_memalign((uptr)align, size, &stack);                \
+    if (!nothrow && UNLIKELY(!res)) {                                    \
+      GET_FATAL_STACK_TRACE;                                             \
+      ReportOutOfMemory(size, &stack);                                   \
+    }                                                                    \
     return res;
 
 INTERCEPTOR_ATTRIBUTE



More information about the cfe-commits mailing list