Skip to content

Commit 1de5a3d

Browse files
committed
[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: #77168
1 parent a127373 commit 1de5a3d

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed

compiler-rt/lib/msan/msan.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,17 @@ const int STACK_TRACE_TAG_VPTR = STACK_TRACE_TAG_FIELDS + 1;
322322
stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal); \
323323
}
324324

325+
#define GET_FATAL_STACK_TRACE \
326+
GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
327+
328+
// Unwind the stack for fatal error, as the parameter `stack` is
329+
// empty without origins.
330+
#define GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(STACK) \
331+
if (msan_inited && (STACK)->size == 0) { \
332+
(STACK)->Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, \
333+
common_flags()->fast_unwind_on_fatal); \
334+
}
335+
325336
class ScopedThreadLocalStateBackup {
326337
public:
327338
ScopedThreadLocalStateBackup() { Backup(); }

compiler-rt/lib/msan/msan_allocator.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,18 @@ void MsanThreadLocalMallocStorage::CommitBack() {
180180

181181
static void *MsanAllocate(BufferedStackTrace *stack, uptr size, uptr alignment,
182182
bool zeroise) {
183-
if (size > max_malloc_size) {
183+
if (UNLIKELY(size > max_malloc_size)) {
184184
if (AllocatorMayReturnNull()) {
185185
Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size);
186186
return nullptr;
187187
}
188+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
188189
ReportAllocationSizeTooBig(size, max_malloc_size, stack);
189190
}
190191
if (UNLIKELY(IsRssLimitExceeded())) {
191192
if (AllocatorMayReturnNull())
192193
return nullptr;
194+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
193195
ReportRssLimitExceeded(stack);
194196
}
195197
MsanThread *t = GetCurrentThread();
@@ -206,6 +208,7 @@ static void *MsanAllocate(BufferedStackTrace *stack, uptr size, uptr alignment,
206208
SetAllocatorOutOfMemory();
207209
if (AllocatorMayReturnNull())
208210
return nullptr;
211+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
209212
ReportOutOfMemory(size, stack);
210213
}
211214
Metadata *meta =
@@ -288,6 +291,7 @@ static void *MsanCalloc(BufferedStackTrace *stack, uptr nmemb, uptr size) {
288291
if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
289292
if (AllocatorMayReturnNull())
290293
return nullptr;
294+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
291295
ReportCallocOverflow(nmemb, size, stack);
292296
}
293297
return MsanAllocate(stack, nmemb * size, sizeof(u64), true);
@@ -344,6 +348,7 @@ void *msan_reallocarray(void *ptr, uptr nmemb, uptr size,
344348
errno = errno_ENOMEM;
345349
if (AllocatorMayReturnNull())
346350
return nullptr;
351+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
347352
ReportReallocArrayOverflow(nmemb, size, stack);
348353
}
349354
return msan_realloc(ptr, nmemb * size, stack);
@@ -359,6 +364,7 @@ void *msan_pvalloc(uptr size, BufferedStackTrace *stack) {
359364
errno = errno_ENOMEM;
360365
if (AllocatorMayReturnNull())
361366
return nullptr;
367+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
362368
ReportPvallocOverflow(size, stack);
363369
}
364370
// pvalloc(0) should allocate one page.
@@ -371,6 +377,7 @@ void *msan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) {
371377
errno = errno_EINVAL;
372378
if (AllocatorMayReturnNull())
373379
return nullptr;
380+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
374381
ReportInvalidAlignedAllocAlignment(size, alignment, stack);
375382
}
376383
return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
@@ -381,6 +388,7 @@ void *msan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack) {
381388
errno = errno_EINVAL;
382389
if (AllocatorMayReturnNull())
383390
return nullptr;
391+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
384392
ReportInvalidAllocationAlignment(alignment, stack);
385393
}
386394
return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
@@ -391,6 +399,7 @@ int msan_posix_memalign(void **memptr, uptr alignment, uptr size,
391399
if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
392400
if (AllocatorMayReturnNull())
393401
return errno_EINVAL;
402+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(stack);
394403
ReportInvalidPosixMemalignAlignment(alignment, stack);
395404
}
396405
void *ptr = MsanAllocate(stack, size, alignment, false);

compiler-rt/lib/msan/msan_new_delete.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,22 @@ namespace std {
3030

3131

3232
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
33-
#define OPERATOR_NEW_BODY(nothrow) \
34-
GET_MALLOC_STACK_TRACE; \
35-
void *res = msan_malloc(size, &stack);\
36-
if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
37-
return res
38-
#define OPERATOR_NEW_BODY_ALIGN(nothrow) \
39-
GET_MALLOC_STACK_TRACE;\
40-
void *res = msan_memalign((uptr)align, size, &stack);\
41-
if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
42-
return res;
33+
# define OPERATOR_NEW_BODY(nothrow) \
34+
GET_MALLOC_STACK_TRACE; \
35+
void *res = msan_malloc(size, &stack); \
36+
if (!nothrow && UNLIKELY(!res)) { \
37+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(&stack); \
38+
ReportOutOfMemory(size, &stack); \
39+
} \
40+
return res
41+
# define OPERATOR_NEW_BODY_ALIGN(nothrow) \
42+
GET_MALLOC_STACK_TRACE; \
43+
void *res = msan_memalign((uptr)align, size, &stack); \
44+
if (!nothrow && UNLIKELY(!res)) { \
45+
GET_FATAL_STACK_TRACE_AGAIN_IF_EMPTY(&stack); \
46+
ReportOutOfMemory(size, &stack); \
47+
} \
48+
return res;
4349

4450
INTERCEPTOR_ATTRIBUTE
4551
void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }

compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
3636
// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
3737
// RUN: %run %t new-nothrow 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
38-
// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
38+
// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0:fast_unwind_on_malloc=0 \
3939
// RUN: not %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-sCRASH
4040
// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
4141
// RUN: %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
@@ -123,20 +123,28 @@ int main(int Argc, char **Argv) {
123123
}
124124

125125
// CHECK-mCRASH: malloc:
126+
// CHECK-mCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
126127
// CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
127128
// CHECK-cCRASH: calloc:
129+
// CHECK-cCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
128130
// CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
129131
// CHECK-rCRASH: realloc:
132+
// CHECK-rCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
130133
// CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
131134
// CHECK-mrCRASH: realloc-after-malloc:
135+
// CHECK-mrCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
132136
// CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
133137
// CHECK-nCRASH: new:
138+
// CHECK-nCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
134139
// CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
135140
// CHECK-nCRASH-OOM: new:
141+
// CHECK-nCRASH-OOM: #{{[0-9]+.*}}max_allocation_size.cpp
136142
// CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory}}
137143
// CHECK-nnCRASH: new-nothrow:
144+
// CHECK-nnCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
138145
// CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
139146
// CHECK-sCRASH: strndup:
147+
// CHECK-sCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
140148
// CHECK-sCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
141149

142150
// CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow|strndup}}

0 commit comments

Comments
 (0)