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