[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