diff options
author | Alexey Samsonov <samsonov@google.com> | 2013-11-13 14:46:58 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2013-11-13 14:46:58 +0000 |
commit | 1b17f5b79d58c5aff291dde05727ad0b215b81c6 (patch) | |
tree | 5ce639a22a08ff9a1b585e1397c01e106ae2d9e9 | |
parent | 348aac42b606dd2d4cec9d68a85bf0144bd7c2f3 (diff) | |
download | compiler-rt-1b17f5b79d58c5aff291dde05727ad0b215b81c6.tar.gz |
[ASan] Do not rely on malloc context in allocator reports.
Invoke a fatal stack trace unwinder when ASan prints allocator-relevant
error reports (double-free, alloc-dealloc-mismatch, invalid-free).
Thus we'll be able to print complete stack trace even if allocation/free
stacks are not stored (malloc_context_size=0).
Based on the patch by Yuri Gribov!
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@194579 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/asan/asan_allocator.h | 2 | ||||
-rw-r--r-- | lib/asan/asan_allocator2.cc | 9 | ||||
-rw-r--r-- | lib/asan/asan_malloc_linux.cc | 5 | ||||
-rw-r--r-- | lib/asan/asan_malloc_win.cc | 5 | ||||
-rw-r--r-- | lib/asan/asan_report.cc | 25 | ||||
-rw-r--r-- | lib/asan/asan_report.h | 6 | ||||
-rw-r--r-- | lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc | 12 | ||||
-rw-r--r-- | lib/asan/lit_tests/TestCases/double-free.cc | 11 | ||||
-rw-r--r-- | lib/asan/lit_tests/TestCases/invalid-free.cc | 9 | ||||
-rw-r--r-- | lib/asan/tests/asan_noinst_test.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_stacktrace.h | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc | 1 |
13 files changed, 60 insertions, 31 deletions
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index 2591bc1b1..c5fcbbb5d 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -115,7 +115,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, StackTrace *stack); -uptr asan_malloc_usable_size(void *ptr, StackTrace *stack); +uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp); uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc index 4b2afb6f9..7a29975d7 100644 --- a/lib/asan/asan_allocator2.cc +++ b/lib/asan/asan_allocator2.cc @@ -664,12 +664,13 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, return 0; } -uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) { - CHECK(stack); +uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) { if (ptr == 0) return 0; uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr)); - if (flags()->check_malloc_usable_size && (usable_size == 0)) - ReportMallocUsableSizeNotOwned((uptr)ptr, stack); + if (flags()->check_malloc_usable_size && (usable_size == 0)) { + GET_STACK_TRACE_FATAL(pc, bp); + ReportMallocUsableSizeNotOwned((uptr)ptr, &stack); + } return usable_size; } diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 20e636b9b..24b7f6977 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -105,8 +105,9 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s) ALIAS("memalign"); INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc_usable_size(ptr, &stack); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(ptr, pc, bp); } // We avoid including malloc.h for portability reasons. diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc index 77c58cb35..73e4c8250 100644 --- a/lib/asan/asan_malloc_win.cc +++ b/lib/asan/asan_malloc_win.cc @@ -98,8 +98,9 @@ void* _recalloc(void* p, size_t n, size_t elem_size) { SANITIZER_INTERFACE_ATTRIBUTE size_t _msize(void *ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc_usable_size(ptr, &stack); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(ptr, pc, bp); } int _CrtDbgReport(int, const char*, int, diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index cbd850ed8..ed4e433c7 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -564,7 +564,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { ReportErrorSummary("SEGV", &stack); } -void ReportDoubleFree(uptr addr, StackTrace *stack) { +void ReportDoubleFree(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -574,14 +574,15 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) { "thread T%d%s:\n", addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportErrorSummary("double-free", stack); + ReportErrorSummary("double-free", &stack); } -void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { +void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -591,12 +592,14 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { "which was not malloc()-ed: %p in thread T%d%s\n", addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportErrorSummary("bad-free", stack); + ReportErrorSummary("bad-free", &stack); } -void ReportAllocTypeMismatch(uptr addr, StackTrace *stack, +void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type) { static const char *alloc_names[] = @@ -610,9 +613,11 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack, Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n", alloc_names[alloc_type], dealloc_names[dealloc_type], addr); Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportErrorSummary("alloc-dealloc-mismatch", stack); + ReportErrorSummary("alloc-dealloc-mismatch", &stack); Report("HINT: if you don't care about these warnings you may set " "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); } diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index db271fc10..f55b57bd4 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -33,9 +33,9 @@ void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr); -void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack); -void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack); -void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack, +void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack); +void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack); +void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type); void NORETURN ReportMallocUsableSizeNotOwned(uptr addr, diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc index c39dcf65e..7010eb2de 100644 --- a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc +++ b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc @@ -2,10 +2,16 @@ // is set. // RUN: %clangxx_asan -g %s -o %t 2>&1 -// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s + +// Find error and provide malloc context. +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK // No error here. // RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t + +// Also works if no malloc context is available. +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s #include <stdlib.h> static volatile char *x; @@ -20,6 +26,6 @@ int main() { // CHECK: #{{.*}}main // CHECK: is located 0 bytes inside of 10-byte region // CHECK-NEXT: allocated by thread T0 here: -// CHECK-NEXT: #0{{.*}}malloc -// CHECK: #{{.*}}main +// ALLOC-STACK-NEXT: #0{{.*}}malloc +// ALLOC-STACK: #{{.*}}main // CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0 diff --git a/lib/asan/lit_tests/TestCases/double-free.cc b/lib/asan/lit_tests/TestCases/double-free.cc index 738a8945c..e66817e91 100644 --- a/lib/asan/lit_tests/TestCases/double-free.cc +++ b/lib/asan/lit_tests/TestCases/double-free.cc @@ -1,4 +1,9 @@ -// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s -o %t 2>&1 +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX + +// Also works if no malloc context is available. +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s #include <stdlib.h> #include <string.h> @@ -11,8 +16,8 @@ int main(int argc, char **argv) { // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0 // CHECK: double-free.cc:[[@LINE-2]] // CHECK: freed by thread T0 here: - // CHECK: double-free.cc:[[@LINE-5]] + // MALLOC-CTX: double-free.cc:[[@LINE-5]] // CHECK: allocated by thread T0 here: - // CHECK: double-free.cc:[[@LINE-10]] + // MALLOC-CTX: double-free.cc:[[@LINE-10]] return res; } diff --git a/lib/asan/lit_tests/TestCases/invalid-free.cc b/lib/asan/lit_tests/TestCases/invalid-free.cc index aeca53656..f940b5012 100644 --- a/lib/asan/lit_tests/TestCases/invalid-free.cc +++ b/lib/asan/lit_tests/TestCases/invalid-free.cc @@ -1,4 +1,9 @@ -// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX + +// Also works if no malloc context is available. +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s #include <stdlib.h> #include <string.h> @@ -11,6 +16,6 @@ int main(int argc, char **argv) { // CHECK: invalid-free.cc:[[@LINE-2]] // CHECK: is located 5 bytes inside of 10-byte region // CHECK: allocated by thread T0 here: - // CHECK: invalid-free.cc:[[@LINE-8]] + // MALLOC-CTX: invalid-free.cc:[[@LINE-8]] return res; } diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index 4c67d6856..cb6223c09 100644 --- a/lib/asan/tests/asan_noinst_test.cc +++ b/lib/asan/tests/asan_noinst_test.cc @@ -106,7 +106,7 @@ static void MallocStress(size_t n) { size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1); char *ptr = (char*)__asan::asan_memalign(alignment, size, &stack2, __asan::FROM_MALLOC); - EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, &stack2)); + EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0)); vec.push_back(ptr); ptr[0] = 0; ptr[size-1] = 0; diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h index 408063c18..88f0a03b1 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/lib/sanitizer_common/sanitizer_stacktrace.h @@ -33,6 +33,7 @@ static const uptr kStackTraceMax = 256; struct StackTrace { typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, int out_size); + uptr top_frame_bp; uptr size; uptr trace[kStackTraceMax]; @@ -41,6 +42,7 @@ struct StackTrace { SymbolizeCallback symbolize_callback = 0); void CopyFrom(const uptr *src, uptr src_size) { + top_frame_bp = 0; size = src_size; if (size > kStackTraceMax) size = kStackTraceMax; for (uptr i = 0; i < size; i++) diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc index a8e70c965..58fa18251 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -21,6 +21,8 @@ void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top, SlowUnwindStack(pc, max_depth); else FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth); + + top_frame_bp = size ? bp : 0; } } // namespace __sanitizer diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc index 5e6d3fdbd..2b842cd81 100644 --- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc @@ -99,6 +99,7 @@ TEST_F(FastUnwindTest, OneFrameStackTrace) { return; EXPECT_EQ(1U, trace.size); EXPECT_EQ(start_pc, trace.trace[0]); + EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp); } } // namespace __sanitizer |