summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2013-11-13 14:46:58 +0000
committerAlexey Samsonov <samsonov@google.com>2013-11-13 14:46:58 +0000
commit1b17f5b79d58c5aff291dde05727ad0b215b81c6 (patch)
tree5ce639a22a08ff9a1b585e1397c01e106ae2d9e9
parent348aac42b606dd2d4cec9d68a85bf0144bd7c2f3 (diff)
downloadcompiler-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.h2
-rw-r--r--lib/asan/asan_allocator2.cc9
-rw-r--r--lib/asan/asan_malloc_linux.cc5
-rw-r--r--lib/asan/asan_malloc_win.cc5
-rw-r--r--lib/asan/asan_report.cc25
-rw-r--r--lib/asan/asan_report.h6
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc12
-rw-r--r--lib/asan/lit_tests/TestCases/double-free.cc11
-rw-r--r--lib/asan/lit_tests/TestCases/invalid-free.cc9
-rw-r--r--lib/asan/tests/asan_noinst_test.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h2
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc2
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc1
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