Index: include/sanitizer/common_interface_defs.h =================================================================== --- include/sanitizer/common_interface_defs.h +++ include/sanitizer/common_interface_defs.h @@ -85,6 +85,9 @@ const void *old_mid, const void *new_mid); + // Print the stack trace leading to this call. Useful for debugging user code. + void __sanitizer_print_stack_trace(); + #ifdef __cplusplus } // extern "C" #endif Index: lib/asan/asan_stack.cc =================================================================== --- lib/asan/asan_stack.cc +++ lib/asan/asan_stack.cc @@ -45,3 +45,11 @@ return false; } #endif + +using namespace __asan; // NOLINT + +SANITIZER_INTERFACE_ATTRIBUTE +extern "C" void __sanitizer_print_stack_trace() { + GET_STACK_TRACE_FATAL_HERE; + PrintStack(&stack); +} Index: lib/lsan/lsan.h =================================================================== --- lib/lsan/lsan.h +++ lib/lsan/lsan.h @@ -14,6 +14,20 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" +#include "lsan_thread.h" + +#define GET_STACK_TRACE(max_size, fast) \ + StackTrace stack; \ + { \ + uptr stack_top = 0, stack_bottom = 0; \ + ThreadContext *t; \ + if (fast && (t = CurrentThreadContext())) { \ + stack_top = t->stack_end(); \ + stack_bottom = t->stack_begin(); \ + } \ + stack.Unwind(max_size, StackTrace::GetCurrentPc(), \ + GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \ + } namespace __lsan { Index: lib/lsan/lsan.cc =================================================================== --- lib/lsan/lsan.cc +++ lib/lsan/lsan.cc @@ -69,3 +69,10 @@ lsan_init_is_running = false; } +// ------------------ Interface -------------- {{{1 + +SANITIZER_INTERFACE_ATTRIBUTE +extern "C" void __sanitizer_print_stack_trace() { + GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) + StackTrace::PrintStack(stack.trace, stack.size); +} Index: lib/lsan/lsan_common.cc =================================================================== --- lib/lsan/lsan_common.cc +++ lib/lsan/lsan_common.cc @@ -535,6 +535,8 @@ } // namespace __lsan #endif // CAN_SANITIZE_LEAKS +// ------------------ Interface -------------- {{{1 + using namespace __lsan; // NOLINT extern "C" { Index: lib/lsan/lsan_interceptors.cc =================================================================== --- lib/lsan/lsan_interceptors.cc +++ lib/lsan/lsan_interceptors.cc @@ -34,20 +34,9 @@ int pthread_setspecific(unsigned key, const void *v); } -#define GET_STACK_TRACE \ - StackTrace stack; \ - { \ - uptr stack_top = 0, stack_bottom = 0; \ - ThreadContext *t; \ - bool fast = common_flags()->fast_unwind_on_malloc; \ - if (fast && (t = CurrentThreadContext())) { \ - stack_top = t->stack_end(); \ - stack_bottom = t->stack_begin(); \ - } \ - stack.Unwind(__sanitizer::common_flags()->malloc_context_size, \ - StackTrace::GetCurrentPc(), \ - GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \ - } +#define GET_STACK_TRACE_MALLOC \ + GET_STACK_TRACE(common_flags()->malloc_context_size, \ + common_flags()->fast_unwind_on_malloc) #define ENSURE_LSAN_INITED do { \ CHECK(!lsan_init_is_running); \ @@ -65,7 +54,7 @@ INTERCEPTOR(void*, malloc, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; return Allocate(stack, size, 1, kAlwaysClearMemory); } @@ -88,26 +77,26 @@ } if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0; ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; size *= nmemb; return Allocate(stack, size, 1, true); } INTERCEPTOR(void*, realloc, void *q, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; return Reallocate(stack, q, size, 1); } INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; return Allocate(stack, size, alignment, kAlwaysClearMemory); } INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory); // FIXME: Return ENOMEM if user requested more than max alloc size. return 0; @@ -115,7 +104,7 @@ INTERCEPTOR(void*, valloc, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; if (size == 0) size = GetPageSizeCached(); return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); @@ -142,7 +131,7 @@ INTERCEPTOR(void*, pvalloc, uptr size) { ENSURE_LSAN_INITED; - GET_STACK_TRACE; + GET_STACK_TRACE_MALLOC; uptr PageSize = GetPageSizeCached(); size = RoundUpTo(size, PageSize); if (size == 0) { @@ -156,7 +145,7 @@ #define OPERATOR_NEW_BODY \ ENSURE_LSAN_INITED; \ - GET_STACK_TRACE; \ + GET_STACK_TRACE_MALLOC; \ return Allocate(stack, size, 1, kAlwaysClearMemory); INTERCEPTOR_ATTRIBUTE Index: lib/msan/msan.cc =================================================================== --- lib/msan/msan.cc +++ lib/msan/msan.cc @@ -192,6 +192,12 @@ stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind); } +// Inlining confuses the slow unwinder in __sanitizer_print_stack_trace(). +NOINLINE void GetStackTraceNoInline(StackTrace *stack, uptr max_s, uptr pc, + uptr bp, bool request_fast_unwind) { + GetStackTrace(stack, max_s, pc, bp, request_fast_unwind); +} + void PrintWarning(uptr pc, uptr bp) { PrintWarningWithOrigin(pc, bp, __msan_origin_tls); } @@ -570,3 +576,14 @@ } // extern "C" #endif +SANITIZER_INTERFACE_ATTRIBUTE +extern "C" void __sanitizer_print_stack_trace() { + StackTrace stack; + stack.size = 0; + if (msan_inited) + GetStackTraceNoInline(&stack, kStackTraceMax, StackTrace::GetCurrentPc(), + GET_CURRENT_FRAME(), + common_flags()->fast_unwind_on_fatal); + StackTrace::PrintStack(stack.trace, stack.size); +} + Index: lib/tsan/rtl/tsan_interface.cc =================================================================== --- lib/tsan/rtl/tsan_interface.cc +++ lib/tsan/rtl/tsan_interface.cc @@ -87,6 +87,11 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_unaligned_store64(void *addr, uint64_t v) ALIAS("__tsan_unaligned_write8"); + +void __sanitizer_print_stack_trace() { + ScopedInRtl in_rtl; + PrintCurrentStackSlow(); +} } void __tsan_acquire(void *addr) {