tsan_report.cc revision 7c9150579ed0278492f51cc8434b1d63a44b9bd1
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" 166d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_common/sanitizer_placement_new.h" 17a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany#include "sanitizer_common/sanitizer_report_decorator.h" 186d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_common/sanitizer_stacktrace_printer.h" 197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan { 217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2286277eb844c4983c81de62d7c050e92fe7155788Stephen HinesReportStack::ReportStack() : frames(nullptr), suppressable(false) {} 236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 2486277eb844c4983c81de62d7c050e92fe7155788Stephen HinesReportStack *ReportStack::New() { 256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack)); 2686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return new(mem) ReportStack(); 276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 296d1862363c88c183b0ed7740fca876342cf0474bStephen HinesReportLocation::ReportLocation(ReportLocationType type) 306d1862363c88c183b0ed7740fca876342cf0474bStephen Hines : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0), 316d1862363c88c183b0ed7740fca876342cf0474bStephen Hines fd(0), suppressable(false), stack(nullptr) {} 326d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 336d1862363c88c183b0ed7740fca876342cf0474bStephen HinesReportLocation *ReportLocation::New(ReportLocationType type) { 346d1862363c88c183b0ed7740fca876342cf0474bStephen Hines void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation)); 356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return new(mem) ReportLocation(type); 366d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 376d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 386a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesclass Decorator: public __sanitizer::SanitizerCommonDecorator { 39a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany public: 406a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines Decorator() : SanitizerCommonDecorator() { } 41a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *Warning() { return Red(); } 42a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *EndWarning() { return Default(); } 43a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *Access() { return Blue(); } 44a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *EndAccess() { return Default(); } 45a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *ThreadDescription() { return Cyan(); } 46a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *EndThreadDescription() { return Default(); } 47a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *Location() { return Green(); } 48a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *EndLocation() { return Default(); } 49a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *Sleep() { return Yellow(); } 50a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *EndSleep() { return Default(); } 51a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *Mutex() { return Magenta(); } 52a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany const char *EndMutex() { return Default(); } 53a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany}; 54a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany 557ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::ReportDesc() 567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany : stacks(MBlockReportStack) 577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany , mops(MBlockReportMop) 587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany , locs(MBlockReportLoc) 597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany , mutexes(MBlockReportMutex) 60848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov , threads(MBlockReportThread) 612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines , unique_tids(MBlockReportThread) 624536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov , sleep() 634536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov , count() { 647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 66ad9da372f962495b3487685232d09390be841b1cDmitry VyukovReportMop::ReportMop() 67ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov : mset(MBlockReportMutex) { 68ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov} 69ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov 707ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() { 71aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov // FIXME(dvyukov): it must be leaking a lot of memory. 727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO 75c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov 76da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst int kThreadBufSize = 32; 77da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst char *thread_name(char *buf, int tid) { 78da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov if (tid == 0) 79da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov return "main thread"; 80da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov internal_snprintf(buf, kThreadBufSize, "thread T%d", tid); 81da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov return buf; 82da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov} 83da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov 842f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic const char *ReportTypeString(ReportType typ) { 857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (typ == ReportTypeRace) 862f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return "data race"; 870dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov if (typ == ReportTypeVptrRace) 880dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov return "data race on vptr (ctor/dtor vs virtual call)"; 892f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (typ == ReportTypeUseAfterFree) 902f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return "heap-use-after-free"; 916d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (typ == ReportTypeVptrUseAfterFree) 926d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return "heap-use-after-free (virtual call vs free)"; 932f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (typ == ReportTypeThreadLeak) 942f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return "thread leak"; 952f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (typ == ReportTypeMutexDestroyLocked) 962f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return "destroy of a locked mutex"; 972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (typ == ReportTypeMutexDoubleLock) 982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return "double lock of a mutex"; 992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (typ == ReportTypeMutexBadUnlock) 1002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return "unlock of an unlocked mutex (or by a wrong thread)"; 1012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (typ == ReportTypeMutexBadReadLock) 1022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return "read lock of a write locked mutex"; 1032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (typ == ReportTypeMutexBadReadUnlock) 1042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return "read unlock of a write locked mutex"; 1052f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (typ == ReportTypeSignalUnsafe) 1062f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return "signal-unsafe call inside of a signal"; 1072f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (typ == ReportTypeErrnoInSignal) 1082f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return "signal handler spoils errno"; 1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (typ == ReportTypeDeadlock) 1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return "lock-order-inversion (potential deadlock)"; 1112f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return ""; 1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1141da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintStack(const ReportStack *ent) { 11586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (ent == 0 || ent->frames == 0) { 11695f50b126cebecc0165fbf6e4c8209c640836271Dmitry Vyukov Printf(" [failed to restore the stack]\n\n"); 117dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov return; 118dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov } 11986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines SymbolizedStack *frame = ent->frames; 12086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines for (int i = 0; frame && frame->info.address; frame = frame->next, i++) { 1216d1862363c88c183b0ed7740fca876342cf0474bStephen Hines InternalScopedString res(2 * GetPageSizeCached()); 12286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info, 1236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines common_flags()->strip_path_prefix, "__interceptor_"); 1246d1862363c88c183b0ed7740fca876342cf0474bStephen Hines Printf("%s\n", res.data()); 1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 126b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("\n"); 1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 129ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovstatic void PrintMutexSet(Vector<ReportMopMutex> const& mset) { 130ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov for (uptr i = 0; i < mset.Size(); i++) { 131ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov if (i == 0) 132ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov Printf(" (mutexes:"); 133ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov const ReportMopMutex m = mset[i]; 134ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov Printf(" %s M%llu", m.write ? "write" : "read", m.id); 135ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov Printf(i == mset.Size() - 1 ? ")" : ","); 136ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov } 137ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov} 138ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov 1390a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukovstatic const char *MopDesc(bool first, bool write, bool atomic) { 1400a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov return atomic ? (first ? (write ? "Atomic write" : "Atomic read") 1410a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov : (write ? "Previous atomic write" : "Previous atomic read")) 1420a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov : (first ? (write ? "Write" : "Read") 1430a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov : (write ? "Previous write" : "Previous read")); 1440a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov} 1450a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov 1467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) { 147a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Decorator d; 148da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov char thrbuf[kThreadBufSize]; 149a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.Access()); 150da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov Printf(" %s of size %d at %p by %s", 1510a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov MopDesc(first, mop->write, mop->atomic), 152da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov mop->size, (void*)mop->addr, 153da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov thread_name(thrbuf, mop->tid)); 154ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov PrintMutexSet(mop->mset); 155ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov Printf(":\n"); 156a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndAccess()); 1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany PrintStack(mop->stack); 1587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) { 161a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Decorator d; 162c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov char thrbuf[kThreadBufSize]; 163a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany bool print_stack = false; 164a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.Location()); 1657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (loc->type == ReportLocationGlobal) { 1666d1862363c88c183b0ed7740fca876342cf0474bStephen Hines const DataInfo &global = loc->global; 167c842dabb53cc2101cc5449f24921a972d812d7c6Alexey Samsonov Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n", 1686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines global.name, global.size, global.start, 1696d1862363c88c183b0ed7740fca876342cf0474bStephen Hines StripModuleName(global.module), global.module_offset); 1707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (loc->type == ReportLocationHeap) { 171da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov char thrbuf[kThreadBufSize]; 172da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov Printf(" Location is heap block of size %zu at %p allocated by %s:\n", 1736d1862363c88c183b0ed7740fca876342cf0474bStephen Hines loc->heap_chunk_size, loc->heap_chunk_start, 1746d1862363c88c183b0ed7740fca876342cf0474bStephen Hines thread_name(thrbuf, loc->tid)); 175a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany print_stack = true; 1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (loc->type == ReportLocationStack) { 177fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid)); 178fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov } else if (loc->type == ReportLocationTLS) { 179fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov Printf(" Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid)); 180c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov } else if (loc->type == ReportLocationFD) { 181c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov Printf(" Location is file descriptor %d created by %s at:\n", 182c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov loc->fd, thread_name(thrbuf, loc->tid)); 183a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany print_stack = true; 1847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 185a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndLocation()); 186a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany if (print_stack) 187a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany PrintStack(loc->stack); 1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintMutexShort(const ReportMutex *rm, const char *after) { 1912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Decorator d; 1922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after); 1932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 1942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintMutexShortWithAddress(const ReportMutex *rm, 1962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines const char *after) { 1972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Decorator d; 1982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after); 1992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 2002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) { 202a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Decorator d; 203ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov if (rm->destroyed) { 204a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.Mutex()); 205ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov Printf(" Mutex M%llu is already destroyed.\n\n", rm->id); 206a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndMutex()); 207ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov } else { 208a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.Mutex()); 2092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr); 210a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndMutex()); 211ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov PrintStack(rm->stack); 212ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov } 2137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 2147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) { 216a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Decorator d; 2177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (rt->id == 0) // Little sense in describing the main thread. 2187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 219a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.ThreadDescription()); 220ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov Printf(" Thread T%d", rt->id); 2212bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov if (rt->name && rt->name[0] != '\0') 222b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf(" '%s'", rt->name); 223da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov char thrbuf[kThreadBufSize]; 224da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov Printf(" (tid=%zu, %s) created by %s", 225da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov rt->pid, rt->running ? "running" : "finished", 226da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov thread_name(thrbuf, rt->parent_tid)); 2277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (rt->stack) 228da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov Printf(" at:"); 229b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("\n"); 230a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndThreadDescription()); 2317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany PrintStack(rt->stack); 2327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 2337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 234848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovstatic void PrintSleep(const ReportStack *s) { 235a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Decorator d; 236a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.Sleep()); 237b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf(" As if synchronized via sleep:\n"); 238a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndSleep()); 239848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov PrintStack(s); 240848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov} 241848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov 2422f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic ReportStack *ChooseSummaryStack(const ReportDesc *rep) { 2432f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (rep->mops.Size()) 2442f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return rep->mops[0]->stack; 2452f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (rep->stacks.Size()) 2462f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return rep->stacks[0]; 2472f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (rep->mutexes.Size()) 2482f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return rep->mutexes[0]->stack; 2492f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany if (rep->threads.Size()) 2502f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return rep->threads[0]->stack; 2512f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany return 0; 2522f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany} 2532f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany 25486277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic bool FrameIsInternal(const SymbolizedStack *frame) { 25586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (frame == 0) 25686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return false; 25786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines const char *file = frame->info.file; 25886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return file != 0 && 25986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines (internal_strstr(file, "tsan_interceptors.cc") || 26086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines internal_strstr(file, "sanitizer_common_interceptors.inc") || 26186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines internal_strstr(file, "tsan_interface_")); 26286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 26386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 26486277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) { 26586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines while (FrameIsInternal(frames) && frames->next) 26686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines frames = frames->next; 26786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return frames; 2682f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany} 2692f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany 2707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) { 271a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Decorator d; 272b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("==================\n"); 2732f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany const char *rep_typ_str = ReportTypeString(rep->typ); 274a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.Warning()); 2750b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, 2760b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne (int)internal_getpid()); 277a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany Printf("%s", d.EndWarning()); 2787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (rep->typ == ReportTypeDeadlock) { 2802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines char thrbuf[kThreadBufSize]; 2812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf(" Cycle in lock order graph: "); 2822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->mutexes.Size(); i++) 2832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMutexShortWithAddress(rep->mutexes[i], " => "); 2842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMutexShort(rep->mutexes[0], "\n\n"); 2852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK_GT(rep->mutexes.Size(), 0U); 2862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1), 2872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines rep->stacks.Size()); 2882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->mutexes.Size(); i++) { 2892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf(" Mutex "); 2902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()], 2912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines " acquired here while holding mutex "); 2922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMutexShort(rep->mutexes[i], " in "); 2932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%s", d.ThreadDescription()); 2942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i])); 2952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%s", d.EndThreadDescription()); 2962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->second_deadlock_stack) { 2972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStack(rep->stacks[2*i]); 2982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf(" Mutex "); 2992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMutexShort(rep->mutexes[i], 3002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines " previously acquired by the same thread here:\n"); 3012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStack(rep->stacks[2*i+1]); 3022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } else { 3032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStack(rep->stacks[i]); 3042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (i == 0) 3052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf(" Hint: use TSAN_OPTIONS=second_deadlock_stack=1 " 3062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "to get more informative warning message\n\n"); 3072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 3082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 3092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } else { 3102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->stacks.Size(); i++) { 3112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (i) 3122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf(" and:\n"); 3132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStack(rep->stacks[i]); 3142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 315332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov } 3167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = 0; i < rep->mops.Size(); i++) 3187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany PrintMop(rep->mops[i], i == 0); 3197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 320848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov if (rep->sleep) 321848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov PrintSleep(rep->sleep); 322848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov 3237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = 0; i < rep->locs.Size(); i++) 3247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany PrintLocation(rep->locs[i]); 3257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (rep->typ != ReportTypeDeadlock) { 3272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->mutexes.Size(); i++) 3282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMutex(rep->mutexes[i]); 3292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 3307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = 0; i < rep->threads.Size(); i++) 3327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany PrintThread(rep->threads[i]); 3337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3344536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov if (rep->typ == ReportTypeThreadLeak && rep->count > 1) 3354536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov Printf(" And %d more similar thread leaks.\n\n", rep->count - 1); 3364536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov 33786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (ReportStack *stack = ChooseSummaryStack(rep)) { 3387c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) 3397c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar ReportErrorSummary(rep_typ_str, frame->info); 3406d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 3412f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany 342b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("==================\n"); 3437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 3447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 34586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#else // #ifndef SANITIZER_GO 3469d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov 3479d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukovconst int kMainThreadId = 1; 348c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov 3490ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukovvoid PrintStack(const ReportStack *ent) { 35086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (ent == 0 || ent->frames == 0) { 3519d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov Printf(" [failed to restore the stack]\n"); 3526c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov return; 3536c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov } 35486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines SymbolizedStack *frame = ent->frames; 35586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines for (int i = 0; frame; frame = frame->next, i++) { 35686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines const AddressInfo &info = frame->info; 35786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Printf(" %s()\n %s:%d +0x%zx\n", info.function, 35886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines StripPathPrefix(info.file, common_flags()->strip_path_prefix), 35986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines info.line, (void *)info.module_offset); 360c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov } 361c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov} 362c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov 363c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) { 3649d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov Printf("\n"); 3659d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov Printf("%s by ", 366c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov (first ? (mop->write ? "Write" : "Read") 3679d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov : (mop->write ? "Previous write" : "Previous read"))); 3689d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov if (mop->tid == kMainThreadId) 3699d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov Printf("main goroutine:\n"); 3709d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov else 3719d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov Printf("goroutine %d:\n", mop->tid); 372c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov PrintStack(mop->stack); 373c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov} 374c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov 37543046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) { 3769d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov if (rt->id == kMainThreadId) 37743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov return; 3789d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov Printf("\n"); 379b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("Goroutine %d (%s) created at:\n", 38043046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov rt->id, rt->running ? "running" : "finished"); 38143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov PrintStack(rt->stack); 38243046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov} 38343046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov 384c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) { 385b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("==================\n"); 3862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (rep->typ == ReportTypeRace) { 3872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("WARNING: DATA RACE"); 3882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->mops.Size(); i++) 3892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintMop(rep->mops[i], i == 0); 3902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->threads.Size(); i++) 3912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintThread(rep->threads[i]); 3922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } else if (rep->typ == ReportTypeDeadlock) { 3932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("WARNING: DEADLOCK\n"); 3942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < rep->mutexes.Size(); i++) { 3952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("Goroutine %d lock mutex %d while holding mutex %d:\n", 3962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 999, rep->mutexes[i]->id, 3972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines rep->mutexes[(i+1) % rep->mutexes.Size()]->id); 3982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStack(rep->stacks[2*i]); 3992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("\n"); 4002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("Mutex %d was previously locked here:\n", 4012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines rep->mutexes[(i+1) % rep->mutexes.Size()]->id); 4022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStack(rep->stacks[2*i + 1]); 4032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("\n"); 4042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 4052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 406b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("==================\n"); 407c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov} 408c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov 409c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif 410c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov 4117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} // namespace __tsan 412