1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_report.cc ----------------------------------------------------===//
27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//                     The LLVM Compiler Infrastructure
47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source
67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details.
77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector.
117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_report.h"
147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h"
157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
16a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany#include "sanitizer_common/sanitizer_report_decorator.h"
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
205d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesclass Decorator: public __sanitizer::SanitizerCommonDecorator {
21a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany public:
225d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  Decorator() : SanitizerCommonDecorator() { }
23a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Warning()    { return Red(); }
24a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndWarning() { return Default(); }
25a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Access()     { return Blue(); }
26a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndAccess()  { return Default(); }
27a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *ThreadDescription()    { return Cyan(); }
28a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndThreadDescription() { return Default(); }
29a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Location()   { return Green(); }
30a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndLocation() { return Default(); }
31a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Sleep()   { return Yellow(); }
32a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndSleep() { return Default(); }
33a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Mutex()   { return Magenta(); }
34a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndMutex() { return Default(); }
35a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany};
36a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany
377ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::ReportDesc()
387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : stacks(MBlockReportStack)
397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mops(MBlockReportMop)
407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , locs(MBlockReportLoc)
417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mutexes(MBlockReportMutex)
42848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , threads(MBlockReportThread)
432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    , unique_tids(MBlockReportThread)
444536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    , sleep()
454536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    , count() {
467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
48ad9da372f962495b3487685232d09390be841b1cDmitry VyukovReportMop::ReportMop()
49ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    : mset(MBlockReportMutex) {
50ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
51ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
527ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() {
53aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  // FIXME(dvyukov): it must be leaking a lot of memory.
547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
56c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#ifndef TSAN_GO
57c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
58da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst int kThreadBufSize = 32;
59da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst char *thread_name(char *buf, int tid) {
60da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  if (tid == 0)
61da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    return "main thread";
62da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
63da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  return buf;
64da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov}
65da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov
662f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic const char *ReportTypeString(ReportType typ) {
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
682f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "data race";
690dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  if (typ == ReportTypeVptrRace)
700dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    return "data race on vptr (ctor/dtor vs virtual call)";
712f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeUseAfterFree)
722f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "heap-use-after-free";
732f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeThreadLeak)
742f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "thread leak";
752f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeMutexDestroyLocked)
762f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "destroy of a locked mutex";
772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexDoubleLock)
782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "double lock of a mutex";
792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexBadUnlock)
802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "unlock of an unlocked mutex (or by a wrong thread)";
812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexBadReadLock)
822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "read lock of a write locked mutex";
832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexBadReadUnlock)
842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "read unlock of a write locked mutex";
852f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeSignalUnsafe)
862f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal-unsafe call inside of a signal";
872f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeErrnoInSignal)
882f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal handler spoils errno";
892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeDeadlock)
902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "lock-order-inversion (potential deadlock)";
912f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return "";
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
941da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintStack(const ReportStack *ent) {
95dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  if (ent == 0) {
9695f50b126cebecc0165fbf6e4c8209c640836271Dmitry Vyukov    Printf("    [failed to restore the stack]\n\n");
97dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov    return;
98dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  }
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; ent; ent = ent->next, i++) {
100b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->col)
102b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(":%d", ent->col);
1037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->module && ent->offset)
104b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
106b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(" (%p)\n", (void*)ent->pc);
1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
108b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
1097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
111ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovstatic void PrintMutexSet(Vector<ReportMopMutex> const& mset) {
112ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset.Size(); i++) {
113ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (i == 0)
114ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      Printf(" (mutexes:");
115ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    const ReportMopMutex m = mset[i];
116ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(" %s M%llu", m.write ? "write" : "read", m.id);
117ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(i == mset.Size() - 1 ? ")" : ",");
118ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
119ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
120ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
1210a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukovstatic const char *MopDesc(bool first, bool write, bool atomic) {
1220a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
1230a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous atomic write" : "Previous atomic read"))
1240a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (first ? (write ? "Write" : "Read")
1250a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous write" : "Previous read"));
1260a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov}
1270a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov
1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) {
129a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
130da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
131a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Access());
132da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf("  %s of size %d at %p by %s",
1330a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov      MopDesc(first, mop->write, mop->atomic),
134da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      mop->size, (void*)mop->addr,
135da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      thread_name(thrbuf, mop->tid));
136ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  PrintMutexSet(mop->mset);
137ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf(":\n");
138a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndAccess());
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(mop->stack);
1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) {
143a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
144c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  char thrbuf[kThreadBufSize];
145a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  bool print_stack = false;
146a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Location());
1477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (loc->type == ReportLocationGlobal) {
148c842dabb53cc2101cc5449f24921a972d812d7c6Alexey Samsonov    Printf("  Location is global '%s' of size %zu at %p (%s+%p)\n\n",
1495a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov               loc->name, loc->size, loc->addr, loc->module, loc->offset);
1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationHeap) {
151da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    char thrbuf[kThreadBufSize];
152da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
153da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov        loc->size, loc->addr, thread_name(thrbuf, loc->tid));
154a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    print_stack = true;
1557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationStack) {
156fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
157fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  } else if (loc->type == ReportLocationTLS) {
158fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid));
159c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  } else if (loc->type == ReportLocationFD) {
160c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    Printf("  Location is file descriptor %d created by %s at:\n",
161c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov        loc->fd, thread_name(thrbuf, loc->tid));
162a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    print_stack = true;
1637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
164a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndLocation());
165a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  if (print_stack)
166a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    PrintStack(loc->stack);
1677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintMutexShort(const ReportMutex *rm, const char *after) {
1702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Decorator d;
1712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after);
1722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintMutexShortWithAddress(const ReportMutex *rm,
1752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                                       const char *after) {
1762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Decorator d;
1772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after);
1782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) {
181a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
182ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (rm->destroyed) {
183a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.Mutex());
184ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf("  Mutex M%llu is already destroyed.\n\n", rm->id);
185a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.EndMutex());
186ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  } else {
187a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.Mutex());
1882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("  Mutex M%llu (%p) created at:\n", rm->id, rm->addr);
189a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.EndMutex());
190ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    PrintStack(rm->stack);
191ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
1927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) {
195a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
1967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->id == 0)  // Little sense in describing the main thread.
1977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
198a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.ThreadDescription());
199ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf("  Thread T%d", rt->id);
2002bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  if (rt->name && rt->name[0] != '\0')
201b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf(" '%s'", rt->name);
202da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
203da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf(" (tid=%zu, %s) created by %s",
204da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    rt->pid, rt->running ? "running" : "finished",
205da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    thread_name(thrbuf, rt->parent_tid));
2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->stack)
207da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf(" at:");
208b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
209a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndThreadDescription());
2107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rt->stack);
2117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
213848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovstatic void PrintSleep(const ReportStack *s) {
214a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
215a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Sleep());
216b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("  As if synchronized via sleep:\n");
217a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndSleep());
218848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  PrintStack(s);
219848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
220848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
2212f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
2222f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mops.Size())
2232f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mops[0]->stack;
2242f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->stacks.Size())
2252f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->stacks[0];
2262f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mutexes.Size())
2272f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mutexes[0]->stack;
2282f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->threads.Size())
2292f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->threads[0]->stack;
2302f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return 0;
2312f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
2322f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
2335ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey SamsonovReportStack *SkipTsanInternalFrames(ReportStack *ent) {
2345ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov  while (FrameIsInternal(ent) && ent->next)
2355ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov    ent = ent->next;
2362f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return ent;
2372f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
2382f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
2397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) {
240a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
241b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
2422f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  const char *rep_typ_str = ReportTypeString(rep->typ);
243a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Warning());
2440b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
2450b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne         (int)internal_getpid());
246a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndWarning());
2477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep->typ == ReportTypeDeadlock) {
2492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    char thrbuf[kThreadBufSize];
2502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("  Cycle in lock order graph: ");
2512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++)
2522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutexShortWithAddress(rep->mutexes[i], " => ");
2532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PrintMutexShort(rep->mutexes[0], "\n\n");
2542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    CHECK_GT(rep->mutexes.Size(), 0U);
2552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1),
2562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines             rep->stacks.Size());
2572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++) {
2582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("  Mutex ");
2592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()],
2602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                      " acquired here while holding mutex ");
2612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutexShort(rep->mutexes[i], " in ");
2622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("%s", d.ThreadDescription());
2632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i]));
2642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("%s", d.EndThreadDescription());
2652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      if (flags()->second_deadlock_stack) {
2662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintStack(rep->stacks[2*i]);
2672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        Printf("  Mutex ");
2682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintMutexShort(rep->mutexes[i],
2692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                        " previously acquired by the same thread here:\n");
2702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintStack(rep->stacks[2*i+1]);
2712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      } else {
2722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintStack(rep->stacks[i]);
2732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        if (i == 0)
2742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          Printf("    Hint: use TSAN_OPTIONS=second_deadlock_stack=1 "
2752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                 "to get more informative warning message\n\n");
2762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      }
2772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
2782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  } else {
2792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->stacks.Size(); i++) {
2802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      if (i)
2812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        Printf("  and:\n");
2822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStack(rep->stacks[i]);
2832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
284332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  }
2857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mops.Size(); i++)
2877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMop(rep->mops[i], i == 0);
2887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
289848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (rep->sleep)
290848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    PrintSleep(rep->sleep);
291848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
2927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->locs.Size(); i++)
2937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintLocation(rep->locs[i]);
2947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep->typ != ReportTypeDeadlock) {
2962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++)
2972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutex(rep->mutexes[i]);
2982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
2997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->threads.Size(); i++)
3017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintThread(rep->threads[i]);
3027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3034536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov  if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
3044536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
3054536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov
3065ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
3072f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
3082f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
309b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
3107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3129d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov#else  // #ifndef TSAN_GO
3139d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov
3149d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukovconst int kMainThreadId = 1;
315c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
3160ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukovvoid PrintStack(const ReportStack *ent) {
3176c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  if (ent == 0) {
3189d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("  [failed to restore the stack]\n");
3196c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov    return;
3206c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  }
321c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (int i = 0; ent; ent = ent->next, i++) {
322b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("  %s()\n      %s:%d +0x%zx\n",
323853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov        ent->func, ent->file, ent->line, (void*)ent->offset);
324c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  }
325c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
326c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
327c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) {
3289d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("\n");
3299d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("%s by ",
330c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      (first ? (mop->write ? "Write" : "Read")
3319d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov             : (mop->write ? "Previous write" : "Previous read")));
3329d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  if (mop->tid == kMainThreadId)
3339d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("main goroutine:\n");
3349d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  else
3359d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("goroutine %d:\n", mop->tid);
336c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  PrintStack(mop->stack);
337c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
338c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
33943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) {
3409d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  if (rt->id == kMainThreadId)
34143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    return;
3429d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("\n");
343b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("Goroutine %d (%s) created at:\n",
34443046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    rt->id, rt->running ? "running" : "finished");
34543046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  PrintStack(rt->stack);
34643046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov}
34743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov
348c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) {
349b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
3502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep->typ == ReportTypeRace) {
3512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("WARNING: DATA RACE");
3522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mops.Size(); i++)
3532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMop(rep->mops[i], i == 0);
3542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->threads.Size(); i++)
3552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintThread(rep->threads[i]);
3562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  } else if (rep->typ == ReportTypeDeadlock) {
3572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("WARNING: DEADLOCK\n");
3582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++) {
3592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("Goroutine %d lock mutex %d while holding mutex %d:\n",
3602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          999, rep->mutexes[i]->id,
3612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
3622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStack(rep->stacks[2*i]);
3632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("\n");
3642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("Mutex %d was previously locked here:\n",
3652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
3662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStack(rep->stacks[2*i + 1]);
3672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("\n");
3682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
3692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
370b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
371c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
372c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
373c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
374c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
3757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
376