[compiler-rt] 8980936 - [msan] Unwind stack before fatal reports (#77168)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 8 17:15:20 PST 2024


Author: Vitaly Buka
Date: 2024-01-08T17:15:16-08:00
New Revision: 898093638043e465a9099829e32614f38cf3e1a8

URL: https://github.com/llvm/llvm-project/commit/898093638043e465a9099829e32614f38cf3e1a8
DIFF: https://github.com/llvm/llvm-project/commit/898093638043e465a9099829e32614f38cf3e1a8.diff

LOG: [msan] Unwind stack before fatal reports (#77168)

Msan does not unwind stack in malloc without origins, but we still need
trace
for fatal errors.

Added: 
    

Modified: 
    compiler-rt/lib/msan/msan.h
    compiler-rt/lib/msan/msan_allocator.cpp
    compiler-rt/lib/msan/msan_new_delete.cpp
    compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h
index 753e6b260734f9..710447a3e1a357 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_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..0b2dd2b2f1883d 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_IF_EMPTY(stack);
     ReportAllocationSizeTooBig(size, max_malloc_size, stack);
   }
   if (UNLIKELY(IsRssLimitExceeded())) {
     if (AllocatorMayReturnNull())
       return nullptr;
+    GET_FATAL_STACK_TRACE_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_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_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_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_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_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_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_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..7daa55474b7dae 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_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_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}}


        


More information about the llvm-commits mailing list