[compiler-rt] r213080 - [ASan] Add ASan debugging API to get malloc/free stack traces and shadow memory mapping info

Kuba Brecka kuba.brecka at gmail.com
Tue Jul 15 10:33:26 PDT 2014


Author: kuba.brecka
Date: Tue Jul 15 12:33:23 2014
New Revision: 213080

URL: http://llvm.org/viewvc/llvm-project?rev=213080&view=rev
Log:
[ASan] Add ASan debugging API to get malloc/free stack traces and shadow memory mapping info

Reviewed at http://reviews.llvm.org/D4466



Added:
    compiler-rt/trunk/lib/asan/asan_debugging.cc
    compiler-rt/trunk/test/asan/TestCases/debug_mapping.cc
    compiler-rt/trunk/test/asan/TestCases/debug_stacks.cc
Modified:
    compiler-rt/trunk/include/sanitizer/asan_interface.h
    compiler-rt/trunk/lib/asan/CMakeLists.txt
    compiler-rt/trunk/lib/asan/asan_interface_internal.h

Modified: compiler-rt/trunk/include/sanitizer/asan_interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/include/sanitizer/asan_interface.h?rev=213080&r1=213079&r2=213080&view=diff
==============================================================================
--- compiler-rt/trunk/include/sanitizer/asan_interface.h (original)
+++ compiler-rt/trunk/include/sanitizer/asan_interface.h Tue Jul 15 12:33:23 2014
@@ -62,6 +62,22 @@ extern "C" {
   // Print the description of addr (useful when debugging in gdb).
   void __asan_describe_address(void *addr);
 
+  // Useful for calling from the debugger to get the allocation stack trace
+  // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+  // returns the number of stored frames or 0 on error.
+  size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
+                                int *thread_id);
+
+  // Useful for calling from the debugger to get the free stack trace
+  // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+  // returns the number of stored frames or 0 on error.
+  size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
+                               int *thread_id);
+
+  // Useful for calling from the debugger to get the current shadow memory
+  // mapping.
+  void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
+
   // This is an internal function that is called to report an error.
   // However it is still a part of the interface because users may want to
   // set a breakpoint on this function in a debugger.

Modified: compiler-rt/trunk/lib/asan/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/CMakeLists.txt?rev=213080&r1=213079&r2=213080&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/asan/CMakeLists.txt Tue Jul 15 12:33:23 2014
@@ -10,6 +10,7 @@ endif()
 set(ASAN_SOURCES
   asan_allocator2.cc
   asan_activation.cc
+  asan_debugging.cc
   asan_fake_stack.cc
   asan_globals.cc
   asan_interceptors.cc

Added: compiler-rt/trunk/lib/asan/asan_debugging.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_debugging.cc?rev=213080&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_debugging.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_debugging.cc Tue Jul 15 12:33:23 2014
@@ -0,0 +1,74 @@
+//===-- asan_debugging.cc -------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file contains various functions that are generally useful to call when
+// using a debugger (LLDB, GDB).
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
+                  bool alloc_stack) {
+  AsanChunkView chunk = FindHeapChunkByAddress(addr);
+  if (!chunk.IsValid()) return 0;
+
+  StackTrace stack;
+  if (alloc_stack) {
+    if (chunk.AllocTid() == kInvalidTid) return 0;
+    chunk.GetAllocStack(&stack);
+    if (thread_id) *thread_id = chunk.AllocTid();
+  } else {
+    if (chunk.FreeTid() == kInvalidTid) return 0;
+    chunk.GetFreeStack(&stack);
+    if (thread_id) *thread_id = chunk.FreeTid();
+  }
+
+  if (trace && size) {
+    if (size > kStackTraceMax)
+      size = kStackTraceMax;
+    if (size > stack.size)
+      size = stack.size;
+    for (uptr i = 0; i < size; i++)
+      trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
+
+    return size;
+  }
+
+  return 0;
+}
+
+}  // namespace __asan
+
+using namespace __asan;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+  return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+  return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
+  if (shadow_scale)
+    *shadow_scale = SHADOW_SCALE;
+  if (shadow_offset)
+    *shadow_offset = SHADOW_OFFSET;
+}

Modified: compiler-rt/trunk/lib/asan/asan_interface_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interface_internal.h?rev=213080&r1=213079&r2=213080&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interface_internal.h (original)
+++ compiler-rt/trunk/lib/asan/asan_interface_internal.h Tue Jul 15 12:33:23 2014
@@ -91,6 +91,17 @@ extern "C" {
   void __asan_describe_address(uptr addr);
 
   SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
+                              u32 *thread_id);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
+                             u32 *thread_id);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
   void __asan_report_error(uptr pc, uptr bp, uptr sp,
                            uptr addr, int is_write, uptr access_size);
 

Added: compiler-rt/trunk/test/asan/TestCases/debug_mapping.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/debug_mapping.cc?rev=213080&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/debug_mapping.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/debug_mapping.cc Tue Jul 15 12:33:23 2014
@@ -0,0 +1,24 @@
+// Checks that the debugging API returns correct shadow scale and offset.
+// RUN: %clangxx_asan -O %s -o %t
+// RUN: env ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// printed because of verbosity=1
+// CHECK: SHADOW_SCALE: [[SCALE:[0-9]+]]
+// CHECK: SHADOW_OFFSET: [[OFFSET:[0-9]+]]
+
+int main() {
+  size_t scale, offset;
+  __asan_get_shadow_mapping(&scale, &offset);
+
+  fprintf(stderr, "scale: %lx\n", scale);
+  fprintf(stderr, "offset: %lx\n", offset);
+
+  // CHECK: scale: [[SCALE]]
+  // CHECK: offset: [[OFFSET]]
+
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/debug_stacks.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/debug_stacks.cc?rev=213080&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/debug_stacks.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/debug_stacks.cc Tue Jul 15 12:33:23 2014
@@ -0,0 +1,62 @@
+// Check that the stack trace debugging API works and returns correct
+// malloc and free stacks.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char *mem;
+void func1() {
+  mem = (char *)malloc(10);
+}
+
+void func2() {
+  free(mem);
+}
+
+int main() {
+  func1();
+  func2();
+
+  void *trace[100];
+  size_t num_frames = 100;
+  int thread_id;
+  num_frames = __asan_get_alloc_stack(mem, trace, num_frames, &thread_id);
+
+  fprintf(stderr, "alloc stack retval %s\n", (num_frames > 0 && num_frames < 10)
+          ? "ok" : "");
+  // CHECK: alloc stack retval ok
+  fprintf(stderr, "thread id = %d\n", thread_id);
+  // CHECK: thread id = 0
+  fprintf(stderr, "0x%lx\n", trace[0]);
+  // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]]
+  fprintf(stderr, "0x%lx\n", trace[1]);
+  // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]]
+
+  num_frames = 100;
+  num_frames = __asan_get_free_stack(mem, trace, num_frames, &thread_id);
+
+  fprintf(stderr, "free stack retval %s\n", (num_frames > 0 && num_frames < 10)
+          ? "ok" : "");
+  // CHECK: free stack retval ok
+  fprintf(stderr, "thread id = %d\n", thread_id);
+  // CHECK: thread id = 0
+  fprintf(stderr, "0x%lx\n", trace[0]);
+  // CHECK: [[FREE_FRAME_0:0x[0-9a-f]+]]
+  fprintf(stderr, "0x%lx\n", trace[1]);
+  // CHECK: [[FREE_FRAME_1:0x[0-9a-f]+]]
+
+  mem[0] = 'A'; // BOOM
+
+  // CHECK: ERROR: AddressSanitizer: heap-use-after-free
+  // CHECK: WRITE of size 1 at 0x{{.*}}
+  // CHECK: freed by thread T0 here:
+  // CHECK: #0 [[FREE_FRAME_0]]
+  // CHECK: #1 [[FREE_FRAME_1]]
+  // CHECK: previously allocated by thread T0 here:
+  // CHECK: #0 [[ALLOC_FRAME_0]]
+  // CHECK: #1 [[ALLOC_FRAME_1]]
+
+  return 0;
+}





More information about the llvm-commits mailing list