summaryrefslogtreecommitdiff
path: root/libsanitizer/tsan/tsan_report.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libsanitizer/tsan/tsan_report.cc')
-rw-r--r--libsanitizer/tsan/tsan_report.cc80
1 files changed, 67 insertions, 13 deletions
diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc
index 098d8262ba13..15ab22b4ba76 100644
--- a/libsanitizer/tsan/tsan_report.cc
+++ b/libsanitizer/tsan/tsan_report.cc
@@ -11,16 +11,35 @@
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
namespace __tsan {
+class Decorator: private __sanitizer::AnsiColorDecorator {
+ public:
+ Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
+ const char *Warning() { return Red(); }
+ const char *EndWarning() { return Default(); }
+ const char *Access() { return Blue(); }
+ const char *EndAccess() { return Default(); }
+ const char *ThreadDescription() { return Cyan(); }
+ const char *EndThreadDescription() { return Default(); }
+ const char *Location() { return Green(); }
+ const char *EndLocation() { return Default(); }
+ const char *Sleep() { return Yellow(); }
+ const char *EndSleep() { return Default(); }
+ const char *Mutex() { return Magenta(); }
+ const char *EndMutex() { return Default(); }
+};
+
ReportDesc::ReportDesc()
: stacks(MBlockReportStack)
, mops(MBlockReportMop)
, locs(MBlockReportLoc)
, mutexes(MBlockReportMutex)
, threads(MBlockReportThread)
- , sleep() {
+ , sleep()
+ , count() {
}
ReportMop::ReportMop()
@@ -44,6 +63,8 @@ const char *thread_name(char *buf, int tid) {
static const char *ReportTypeString(ReportType typ) {
if (typ == ReportTypeRace)
return "data race";
+ if (typ == ReportTypeVptrRace)
+ return "data race on vptr (ctor/dtor vs virtual call)";
if (typ == ReportTypeUseAfterFree)
return "heap-use-after-free";
if (typ == ReportTypeThreadLeak)
@@ -92,18 +113,24 @@ static const char *MopDesc(bool first, bool write, bool atomic) {
}
static void PrintMop(const ReportMop *mop, bool first) {
+ Decorator d;
char thrbuf[kThreadBufSize];
+ Printf("%s", d.Access());
Printf(" %s of size %d at %p by %s",
MopDesc(first, mop->write, mop->atomic),
mop->size, (void*)mop->addr,
thread_name(thrbuf, mop->tid));
PrintMutexSet(mop->mset);
Printf(":\n");
+ Printf("%s", d.EndAccess());
PrintStack(mop->stack);
}
static void PrintLocation(const ReportLocation *loc) {
+ Decorator d;
char thrbuf[kThreadBufSize];
+ bool print_stack = false;
+ Printf("%s", d.Location());
if (loc->type == ReportLocationGlobal) {
Printf(" Location is global '%s' of size %zu at %zx (%s+%p)\n\n",
loc->name, loc->size, loc->addr, loc->module, loc->offset);
@@ -111,7 +138,7 @@ static void PrintLocation(const ReportLocation *loc) {
char thrbuf[kThreadBufSize];
Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
loc->size, loc->addr, thread_name(thrbuf, loc->tid));
- PrintStack(loc->stack);
+ print_stack = true;
} else if (loc->type == ReportLocationStack) {
Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
} else if (loc->type == ReportLocationTLS) {
@@ -119,24 +146,34 @@ static void PrintLocation(const ReportLocation *loc) {
} else if (loc->type == ReportLocationFD) {
Printf(" Location is file descriptor %d created by %s at:\n",
loc->fd, thread_name(thrbuf, loc->tid));
- PrintStack(loc->stack);
+ print_stack = true;
}
+ Printf("%s", d.EndLocation());
+ if (print_stack)
+ PrintStack(loc->stack);
}
static void PrintMutex(const ReportMutex *rm) {
+ Decorator d;
if (rm->destroyed) {
+ Printf("%s", d.Mutex());
Printf(" Mutex M%llu is already destroyed.\n\n", rm->id);
+ Printf("%s", d.EndMutex());
} else {
+ Printf("%s", d.Mutex());
Printf(" Mutex M%llu created at:\n", rm->id);
+ Printf("%s", d.EndMutex());
PrintStack(rm->stack);
}
}
static void PrintThread(const ReportThread *rt) {
+ Decorator d;
if (rt->id == 0) // Little sense in describing the main thread.
return;
+ Printf("%s", d.ThreadDescription());
Printf(" Thread T%d", rt->id);
- if (rt->name)
+ if (rt->name && rt->name[0] != '\0')
Printf(" '%s'", rt->name);
char thrbuf[kThreadBufSize];
Printf(" (tid=%zu, %s) created by %s",
@@ -145,11 +182,15 @@ static void PrintThread(const ReportThread *rt) {
if (rt->stack)
Printf(" at:");
Printf("\n");
+ Printf("%s", d.EndThreadDescription());
PrintStack(rt->stack);
}
static void PrintSleep(const ReportStack *s) {
+ Decorator d;
+ Printf("%s", d.Sleep());
Printf(" As if synchronized via sleep:\n");
+ Printf("%s", d.EndSleep());
PrintStack(s);
}
@@ -172,9 +213,13 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
}
void PrintReport(const ReportDesc *rep) {
+ Decorator d;
Printf("==================\n");
const char *rep_typ_str = ReportTypeString(rep->typ);
- Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
+ Printf("%s", d.Warning());
+ Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
+ (int)internal_getpid());
+ Printf("%s", d.EndWarning());
for (uptr i = 0; i < rep->stacks.Size(); i++) {
if (i)
@@ -197,37 +242,46 @@ void PrintReport(const ReportDesc *rep) {
for (uptr i = 0; i < rep->threads.Size(); i++)
PrintThread(rep->threads[i]);
+ if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
+ Printf(" And %d more similar thread leaks.\n\n", rep->count - 1);
+
if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
Printf("==================\n");
}
-#else
+#else // #ifndef TSAN_GO
+
+const int kMainThreadId = 1;
void PrintStack(const ReportStack *ent) {
if (ent == 0) {
- Printf(" [failed to restore the stack]\n\n");
+ Printf(" [failed to restore the stack]\n");
return;
}
for (int i = 0; ent; ent = ent->next, i++) {
Printf(" %s()\n %s:%d +0x%zx\n",
ent->func, ent->file, ent->line, (void*)ent->offset);
}
- Printf("\n");
}
static void PrintMop(const ReportMop *mop, bool first) {
- Printf("%s by goroutine %d:\n",
+ Printf("\n");
+ Printf("%s by ",
(first ? (mop->write ? "Write" : "Read")
- : (mop->write ? "Previous write" : "Previous read")),
- mop->tid);
+ : (mop->write ? "Previous write" : "Previous read")));
+ if (mop->tid == kMainThreadId)
+ Printf("main goroutine:\n");
+ else
+ Printf("goroutine %d:\n", mop->tid);
PrintStack(mop->stack);
}
static void PrintThread(const ReportThread *rt) {
- if (rt->id == 0) // Little sense in describing the main thread.
+ if (rt->id == kMainThreadId)
return;
+ Printf("\n");
Printf("Goroutine %d (%s) created at:\n",
rt->id, rt->running ? "running" : "finished");
PrintStack(rt->stack);
@@ -235,7 +289,7 @@ static void PrintThread(const ReportThread *rt) {
void PrintReport(const ReportDesc *rep) {
Printf("==================\n");
- Printf("WARNING: DATA RACE\n");
+ 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->threads.Size(); i++)