From a029b79e1a71b46b3e8d0ace236a2d935643cf7b Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 1 Mar 2016 15:38:12 +0000 Subject: [PATCH] tsan: describe heap/data locations in Go llvm-svn: 262343 --- .../lib/sanitizer_common/sanitizer_symbolizer.cc | 1 + .../lib/sanitizer_common/sanitizer_symbolizer.h | 2 + compiler-rt/lib/tsan/go/test.c | 13 ++-- compiler-rt/lib/tsan/go/tsan_go.cc | 90 ++++++++++++++++------ compiler-rt/lib/tsan/rtl/tsan_report.cc | 31 +++++++- compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc | 2 +- 6 files changed, 108 insertions(+), 31 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc index 6e271c0..534e55f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc @@ -60,6 +60,7 @@ DataInfo::DataInfo() { void DataInfo::Clear() { InternalFree(module); + InternalFree(file); InternalFree(name); internal_memset(this, 0, sizeof(DataInfo)); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h index a1d4d00..edf487f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h @@ -65,6 +65,8 @@ struct DataInfo { // (de)allocated using sanitizer internal allocator. char *module; uptr module_offset; + char *file; + uptr line; char *name; uptr start; uptr size; diff --git a/compiler-rt/lib/tsan/go/test.c b/compiler-rt/lib/tsan/go/test.c index 94433f1..0019967 100644 --- a/compiler-rt/lib/tsan/go/test.c +++ b/compiler-rt/lib/tsan/go/test.c @@ -13,7 +13,7 @@ #include -void __tsan_init(void **thr, void (*cb)(void*)); +void __tsan_init(void **thr, void (*cb)(long, void*)); void __tsan_fini(); void __tsan_map_shadow(void *addr, unsigned long size); void __tsan_go_start(void *thr, void **chthr, void *pc); @@ -22,12 +22,12 @@ void __tsan_read(void *thr, void *addr, void *pc); void __tsan_write(void *thr, void *addr, void *pc); void __tsan_func_enter(void *thr, void *pc); void __tsan_func_exit(void *thr); -void __tsan_malloc(void *p, unsigned long sz); +void __tsan_malloc(void *thr, void *pc, void *p, unsigned long sz); void __tsan_acquire(void *thr, void *addr); void __tsan_release(void *thr, void *addr); void __tsan_release_merge(void *thr, void *addr); -void symbolize_cb(void *ctx) {} +void symbolize_cb(long cmd, void *ctx) {} char buf0[100<<10]; @@ -36,12 +36,13 @@ void barfoo() {} int main(void) { void *thr0 = 0; - char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1)); - __tsan_malloc(buf, 10); __tsan_init(&thr0, symbolize_cb); + char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1)); __tsan_map_shadow(buf, 4096); + __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10); + __tsan_free(thr0, buf, 10); __tsan_func_enter(thr0, (char*)&main + 1); - __tsan_malloc(buf, 10); + __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10); __tsan_release(thr0, buf); __tsan_release_merge(thr0, buf); void *thr1 = 0; diff --git a/compiler-rt/lib/tsan/go/tsan_go.cc b/compiler-rt/lib/tsan/go/tsan_go.cc index ea0beb7..b9f4934 100644 --- a/compiler-rt/lib/tsan/go/tsan_go.cc +++ b/compiler-rt/lib/tsan/go/tsan_go.cc @@ -28,10 +28,6 @@ bool IsExpectedReport(uptr addr, uptr size) { return false; } -ReportLocation *SymbolizeData(uptr addr) { - return 0; -} - void *internal_alloc(MBlockType typ, uptr sz) { return InternalAlloc(sz); } @@ -40,7 +36,15 @@ void internal_free(void *p) { InternalFree(p); } -struct SymbolizeContext { +// Callback into Go. +static void (*go_runtime_cb)(uptr cmd, void *ctx); + +enum { + CallbackSymbolizeCode = 0, + CallbackSymbolizeData = 1, +}; + +struct SymbolizeCodeContext { uptr pc; char *func; char *file; @@ -49,26 +53,62 @@ struct SymbolizeContext { uptr res; }; -// Callback into Go. -static void (*symbolize_cb)(SymbolizeContext *ctx); - SymbolizedStack *SymbolizeCode(uptr addr) { SymbolizedStack *s = SymbolizedStack::New(addr); - SymbolizeContext ctx; - internal_memset(&ctx, 0, sizeof(ctx)); - ctx.pc = addr; - symbolize_cb(&ctx); - if (ctx.res) { + SymbolizeCodeContext cbctx; + internal_memset(&cbctx, 0, sizeof(cbctx)); + cbctx.pc = addr; + go_runtime_cb(CallbackSymbolizeCode, &cbctx); + if (cbctx.res) { AddressInfo &info = s->info; - info.module_offset = ctx.off; - info.function = internal_strdup(ctx.func ? ctx.func : "??"); - info.file = internal_strdup(ctx.file ? ctx.file : "-"); - info.line = ctx.line; + info.module_offset = cbctx.off; + info.function = internal_strdup(cbctx.func ? cbctx.func : "??"); + info.file = internal_strdup(cbctx.file ? cbctx.file : "-"); + info.line = cbctx.line; info.column = 0; } return s; } +struct SymbolizeDataContext { + uptr addr; + uptr heap; + uptr start; + uptr size; + char *name; + char *file; + uptr line; + uptr res; +}; + +ReportLocation *SymbolizeData(uptr addr) { + SymbolizeDataContext cbctx; + internal_memset(&cbctx, 0, sizeof(cbctx)); + cbctx.addr = addr; + go_runtime_cb(CallbackSymbolizeData, &cbctx); + if (!cbctx.res) + return 0; + if (cbctx.heap) { + MBlock *b = ctx->metamap.GetBlock(cbctx.start); + if (!b) + return 0; + ReportLocation *loc = ReportLocation::New(ReportLocationHeap); + loc->heap_chunk_start = cbctx.start; + loc->heap_chunk_size = b->siz; + loc->tid = b->tid; + loc->stack = SymbolizeStackId(b->stk); + return loc; + } else { + ReportLocation *loc = ReportLocation::New(ReportLocationGlobal); + loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??"); + loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??"); + loc->global.line = cbctx.line; + loc->global.start = cbctx.start; + loc->global.size = cbctx.size; + return loc; + } +} + extern "C" { static ThreadState *main_thr; @@ -81,8 +121,8 @@ static ThreadState *AllocGoroutine() { return thr; } -void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) { - symbolize_cb = cb; +void __tsan_init(ThreadState **thrp, void (*cb)(uptr cmd, void *cb)) { + go_runtime_cb = cb; ThreadState *thr = AllocGoroutine(); main_thr = *thrp = thr; Initialize(thr); @@ -140,12 +180,18 @@ void __tsan_func_exit(ThreadState *thr) { FuncExit(thr); } -void __tsan_malloc(void *p, uptr sz) { - if (!inited) - return; +void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) { + CHECK(inited); + if (thr && pc) + ctx->metamap.AllocBlock(thr, pc, p, sz); MemoryResetRange(0, 0, (uptr)p, sz); } +void __tsan_free(ThreadState *thr, uptr p, uptr sz) { + if (thr) + ctx->metamap.FreeRange(thr, 0, p, sz); +} + void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) { ThreadState *thr = AllocGoroutine(); *pthr = thr; diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cc b/compiler-rt/lib/tsan/rtl/tsan_report.cc index c1d2fd0..1b7a62c 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_report.cc @@ -379,9 +379,9 @@ void PrintStack(const ReportStack *ent) { static void PrintMop(const ReportMop *mop, bool first) { Printf("\n"); - Printf("%s by ", + Printf("%s at %p by ", (first ? (mop->write ? "Write" : "Read") - : (mop->write ? "Previous write" : "Previous read"))); + : (mop->write ? "Previous write" : "Previous read")), mop->addr); if (mop->tid == kMainThreadId) Printf("main goroutine:\n"); else @@ -389,6 +389,31 @@ static void PrintMop(const ReportMop *mop, bool first) { PrintStack(mop->stack); } +static void PrintLocation(const ReportLocation *loc) { + switch (loc->type) { + case ReportLocationHeap: { + Printf("\n"); + Printf("Heap block of size %zu at %p allocated by ", + loc->heap_chunk_size, loc->heap_chunk_start); + if (loc->tid == kMainThreadId) + Printf("main goroutine:\n"); + else + Printf("goroutine %d:\n", loc->tid); + PrintStack(loc->stack); + break; + } + case ReportLocationGlobal: { + Printf("\n"); + Printf("Global var %s of size %zu at %p declared at %s:%zu\n", + loc->global.name, loc->global.size, loc->global.start, + loc->global.file, loc->global.line); + break; + } + default: + break; + } +} + static void PrintThread(const ReportThread *rt) { if (rt->id == kMainThreadId) return; @@ -404,6 +429,8 @@ void PrintReport(const ReportDesc *rep) { Printf("WARNING: DATA RACE"); for (uptr i = 0; i < rep->mops.Size(); i++) PrintMop(rep->mops[i], i == 0); + for (uptr i = 0; i < rep->locs.Size(); i++) + PrintLocation(rep->locs[i]); for (uptr i = 0; i < rep->threads.Size(); i++) PrintThread(rep->threads[i]); } else if (rep->typ == ReportTypeDeadlock) { diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc index 5aff6ca..bb327a3 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc @@ -342,12 +342,12 @@ void ScopedReport::AddLocation(uptr addr, uptr size) { rep_->locs.PushBack(loc); AddThread(tctx); } +#endif if (ReportLocation *loc = SymbolizeData(addr)) { loc->suppressable = true; rep_->locs.PushBack(loc); return; } -#endif } #ifndef SANITIZER_GO -- 2.7.4