[compiler-rt] r290119 - [tsan] Implement __tsan_get_alloc_stack and __tsan_locate_address to query pointer types and allocation stacks of heap pointers

Kuba Mracek via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 19 09:52:21 PST 2016


Author: kuba.brecka
Date: Mon Dec 19 11:52:20 2016
New Revision: 290119

URL: http://llvm.org/viewvc/llvm-project?rev=290119&view=rev
Log:
[tsan] Implement __tsan_get_alloc_stack and __tsan_locate_address to query pointer types and allocation stacks of heap pointers

In ASan, we have __asan_locate_address and __asan_get_alloc_stack, which is used in LLDB/Xcode to show the allocation backtrace for a heap memory object. This patch implements the same for TSan.

Differential Revision: https://reviews.llvm.org/D27656


Added:
    compiler-rt/trunk/test/tsan/debug_alloc_stack.cc
    compiler-rt/trunk/test/tsan/debug_locate.cc
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc?rev=290119&r1=290118&r2=290119&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_debugging.cc Mon Dec 19 11:52:20 2016
@@ -15,6 +15,8 @@
 #include "tsan_report.h"
 #include "tsan_rtl.h"
 
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
 using namespace __tsan;
 
 static const char *ReportTypeDescription(ReportType typ) {
@@ -160,3 +162,78 @@ int __tsan_get_report_unique_tid(void *r
   *tid = rep->unique_tids[idx];
   return 1;
 }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,
+                                  uptr *region_address_ptr,
+                                  uptr *region_size_ptr) {
+  uptr region_address = 0;
+  uptr region_size = 0;
+  const char *region_kind = nullptr;
+  if (name && name_size > 0) name[0] = 0;
+
+  if (IsMetaMem(addr)) {
+    region_kind = "meta shadow";
+  } else if (IsShadowMem(addr)) {
+    region_kind = "shadow";
+  } else {
+    bool is_stack = false;
+    MBlock *b = 0;
+    Allocator *a = allocator();
+    if (a->PointerIsMine((void *)addr)) {
+      void *block_begin = a->GetBlockBegin((void *)addr);
+      if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
+    }
+
+    if (b != 0) {
+      region_address = (uptr)allocator()->GetBlockBegin((void *)addr);
+      region_size = b->siz;
+      region_kind = "heap";
+    } else {
+      // TODO(kuba.brecka): We should not lock. This is supposed to be called
+      // from within the debugger when other threads are stopped.
+      ctx->thread_registry->Lock();
+      ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack);
+      ctx->thread_registry->Unlock();
+      if (tctx) {
+        region_kind = is_stack ? "stack" : "tls";
+      } else {
+        region_kind = "global";
+        DataInfo info;
+        if (Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) {
+          internal_strncpy(name, info.name, name_size);
+          region_address = info.start;
+          region_size = info.size;
+        }
+      }
+    }
+  }
+
+  CHECK(region_kind);
+  if (region_address_ptr) *region_address_ptr = region_address;
+  if (region_size_ptr) *region_size_ptr = region_size;
+  return region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,
+                           uptr *os_id) {
+  MBlock *b = 0;
+  Allocator *a = allocator();
+  if (a->PointerIsMine((void *)addr)) {
+    void *block_begin = a->GetBlockBegin((void *)addr);
+    if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
+  }
+  if (b == 0) return 0;
+
+  *thread_id = b->tid;
+  // No locking.  This is supposed to be called from within the debugger when
+  // other threads are stopped.
+  ThreadContextBase *tctx = ctx->thread_registry->GetThreadLocked(b->tid);
+  *os_id = tctx->os_id;
+
+  StackTrace stack = StackDepotGet(b->stk);
+  size = Min(size, (uptr)stack.size);
+  for (uptr i = 0; i < size; i++) trace[i] = stack.trace[stack.size - i - 1];
+  return size;
+}

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h?rev=290119&r1=290118&r2=290119&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface.h Mon Dec 19 11:52:20 2016
@@ -136,6 +136,17 @@ int __tsan_get_report_thread(void *repor
 SANITIZER_INTERFACE_ATTRIBUTE
 int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid);
 
+// Returns the type of the pointer (heap, stack, global, ...) and if possible
+// also the starting address (e.g. of a heap allocation) and size.
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,
+                                  uptr *region_address, uptr *region_size);
+
+// Returns the allocation stack for a heap pointer.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,
+                           uptr *os_id);
+
 #endif  // SANITIZER_GO
 
 #ifdef __cplusplus

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=290119&r1=290118&r2=290119&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Mon Dec 19 11:52:20 2016
@@ -590,6 +590,7 @@ class ScopedReport {
   void operator = (const ScopedReport&);
 };
 
+ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
 void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
                   MutexSet *mset);
 

Added: compiler-rt/trunk/test/tsan/debug_alloc_stack.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/debug_alloc_stack.cc?rev=290119&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/debug_alloc_stack.cc (added)
+++ compiler-rt/trunk/test/tsan/debug_alloc_stack.cc Mon Dec 19 11:52:20 2016
@@ -0,0 +1,80 @@
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: env %env_tsan_opts=stack_trace_format=DEFAULT %deflake %run %t 2>&1 | FileCheck %s
+
+#include "test.h"
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if !__APPLE__
+#include <sys/types.h>
+#endif
+
+extern "C" int __tsan_get_alloc_stack(void *addr, void **trace, size_t size,
+                                      int *thread_id, void *os_id);
+
+char *mem;
+void alloc_func() { mem = (char *)malloc(10); }
+
+void *AllocThread(void *context) {
+  uint64_t tid;
+#if __APPLE__
+  pthread_threadid_np(NULL, &tid);
+#else
+  tid = gettid();
+#endif
+  fprintf(stderr, "alloc stack thread os id = 0x%llx\n", tid);
+  // CHECK: alloc stack thread os id = [[THREAD_OS_ID:0x[0-9a-f]+]]
+  alloc_func();
+  return NULL;
+}
+
+void *RaceThread(void *context) {
+  *mem = 'a';
+  barrier_wait(&barrier);
+  return NULL;
+}
+
+int main() {
+  pthread_t t;
+  barrier_init(&barrier, 2);
+
+  pthread_create(&t, NULL, AllocThread, NULL);
+  pthread_join(t, NULL);
+
+  void *trace[100];
+  size_t num_frames = 100;
+  int thread_id;
+  void *thread_os_id;
+  num_frames =
+      __tsan_get_alloc_stack(mem, trace, num_frames, &thread_id, &thread_os_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 = 1
+  fprintf(stderr, "thread os id = 0x%llx\n", (uint64_t)thread_os_id);
+  // CHECK: thread os id = [[THREAD_OS_ID]]
+  fprintf(stderr, "%p\n", trace[0]);
+  // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]]
+  fprintf(stderr, "%p\n", trace[1]);
+  // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]]
+  fprintf(stderr, "%p\n", trace[2]);
+  // CHECK: [[ALLOC_FRAME_2:0x[0-9a-f]+]]
+
+  pthread_create(&t, NULL, RaceThread, NULL);
+  barrier_wait(&barrier);
+  mem[0] = 'b';
+  pthread_join(t, NULL);
+
+  free(mem);
+
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is heap block of size 10 at {{.*}} allocated by thread T1
+// CHECK: #0 [[ALLOC_FRAME_0]]
+// CHECK: #1 [[ALLOC_FRAME_1]] in alloc_func
+// CHECK: #2 [[ALLOC_FRAME_2]] in AllocThread

Added: compiler-rt/trunk/test/tsan/debug_locate.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/debug_locate.cc?rev=290119&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/debug_locate.cc (added)
+++ compiler-rt/trunk/test/tsan/debug_locate.cc Mon Dec 19 11:52:20 2016
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" const char *
+__tsan_locate_address(void *addr, char *name, size_t name_size,
+                      void **region_address_ptr, size_t *region_size_ptr);
+
+long global_var;
+
+int main() {
+  long stack_var;
+  void *heap_var = malloc(10);
+
+  fprintf(stderr, "stack_var = %p\n", &stack_var);
+  fprintf(stderr, "global_var = %p\n", &global_var);
+  fprintf(stderr, "heap_var = %p\n", heap_var);
+  // CHECK: stack_var = [[STACK_VAR:0x[0-9a-f]+]]
+  // CHECK: global_var = [[GLOBAL_VAR:0x[0-9a-f]+]]
+  // CHECK: heap_var = [[HEAP_VAR:0x[0-9a-f]+]]
+
+  const char *type;
+  char name[128];
+  void *start;
+  size_t size;
+  type = __tsan_locate_address(&stack_var, name, 128, &start, &size);
+  fprintf(stderr, "type: %s\n", type);
+  // CHECK: type: stack
+
+  type = __tsan_locate_address(&global_var, name, 128, &start, &size);
+  fprintf(stderr, "type: %s, name = %s, start = %p, size = %zu\n", type, name,
+          start, size);
+  // CHECK: type: global, name = global_var, start = [[GLOBAL_VAR]], size = 8
+
+  type = __tsan_locate_address(heap_var, name, 128, &start, &size);
+  fprintf(stderr, "type: %s, start = %p, size = %zu\n", type, start, size);
+  // CHECK: type: heap, start = [[HEAP_VAR]], size = 10
+
+  free(heap_var);
+  return 0;
+}




More information about the llvm-commits mailing list