tsan: describe heap/data locations in Go

llvm-svn: 262343
This commit is contained in:
Dmitry Vyukov 2016-03-01 15:38:12 +00:00
parent f5fcdd268f
commit a029b79e1a
6 changed files with 108 additions and 31 deletions

View File

@ -60,6 +60,7 @@ DataInfo::DataInfo() {
void DataInfo::Clear() {
InternalFree(module);
InternalFree(file);
InternalFree(name);
internal_memset(this, 0, sizeof(DataInfo));
}

View File

@ -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;

View File

@ -13,7 +13,7 @@
#include <stdio.h>
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;

View File

@ -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;

View File

@ -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) {

View File

@ -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