1//===-- tsan_report.cc ----------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of ThreadSanitizer (TSan), a race detector. 11// 12//===----------------------------------------------------------------------===// 13#include "tsan_report.h" 14#include "tsan_platform.h" 15#include "tsan_rtl.h" 16 17namespace __tsan { 18 19ReportDesc::ReportDesc() 20 : stacks(MBlockReportStack) 21 , mops(MBlockReportMop) 22 , locs(MBlockReportLoc) 23 , mutexes(MBlockReportMutex) 24 , threads(MBlockReportThread) 25 , sleep() { 26} 27 28ReportDesc::~ReportDesc() { 29} 30 31#ifndef TSAN_GO 32 33static void PrintHeader(ReportType typ) { 34 TsanPrintf("WARNING: ThreadSanitizer: "); 35 36 if (typ == ReportTypeRace) 37 TsanPrintf("data race"); 38 else if (typ == ReportTypeUseAfterFree) 39 TsanPrintf("heap-use-after-free"); 40 else if (typ == ReportTypeThreadLeak) 41 TsanPrintf("thread leak"); 42 else if (typ == ReportTypeMutexDestroyLocked) 43 TsanPrintf("destroy of a locked mutex"); 44 else if (typ == ReportTypeSignalUnsafe) 45 TsanPrintf("signal-unsafe call inside of a signal"); 46 else if (typ == ReportTypeErrnoInSignal) 47 TsanPrintf("signal handler spoils errno"); 48 49 TsanPrintf(" (pid=%d)\n", GetPid()); 50} 51 52void PrintStack(const ReportStack *ent) { 53 for (int i = 0; ent; ent = ent->next, i++) { 54 TsanPrintf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line); 55 if (ent->col) 56 TsanPrintf(":%d", ent->col); 57 if (ent->module && ent->offset) 58 TsanPrintf(" (%s+%p)\n", ent->module, (void*)ent->offset); 59 else 60 TsanPrintf(" (%p)\n", (void*)ent->pc); 61 } 62 TsanPrintf("\n"); 63} 64 65static void PrintMop(const ReportMop *mop, bool first) { 66 TsanPrintf(" %s of size %d at %p", 67 (first ? (mop->write ? "Write" : "Read") 68 : (mop->write ? "Previous write" : "Previous read")), 69 mop->size, (void*)mop->addr); 70 if (mop->tid == 0) 71 TsanPrintf(" by main thread:\n"); 72 else 73 TsanPrintf(" by thread %d:\n", mop->tid); 74 PrintStack(mop->stack); 75} 76 77static void PrintLocation(const ReportLocation *loc) { 78 if (loc->type == ReportLocationGlobal) { 79 TsanPrintf(" Location is global '%s' of size %zu at %zx %s:%d\n", 80 loc->name, loc->size, loc->addr, loc->file, loc->line); 81 } else if (loc->type == ReportLocationHeap) { 82 TsanPrintf(" Location is heap block of size %zu at %p allocated", 83 loc->size, loc->addr); 84 if (loc->tid == 0) 85 TsanPrintf(" by main thread:\n"); 86 else 87 TsanPrintf(" by thread %d:\n", loc->tid); 88 PrintStack(loc->stack); 89 } else if (loc->type == ReportLocationStack) { 90 TsanPrintf(" Location is stack of thread %d:\n", loc->tid); 91 } 92} 93 94static void PrintMutex(const ReportMutex *rm) { 95 if (rm->stack == 0) 96 return; 97 TsanPrintf(" Mutex %d created at:\n", rm->id); 98 PrintStack(rm->stack); 99} 100 101static void PrintThread(const ReportThread *rt) { 102 if (rt->id == 0) // Little sense in describing the main thread. 103 return; 104 TsanPrintf(" Thread %d", rt->id); 105 if (rt->name) 106 TsanPrintf(" '%s'", rt->name); 107 TsanPrintf(" (%s)", rt->running ? "running" : "finished"); 108 if (rt->stack) 109 TsanPrintf(" created at:"); 110 TsanPrintf("\n"); 111 PrintStack(rt->stack); 112} 113 114static void PrintSleep(const ReportStack *s) { 115 TsanPrintf(" As if synchronized via sleep:\n"); 116 PrintStack(s); 117} 118 119void PrintReport(const ReportDesc *rep) { 120 TsanPrintf("==================\n"); 121 PrintHeader(rep->typ); 122 123 for (uptr i = 0; i < rep->stacks.Size(); i++) { 124 if (i) 125 TsanPrintf(" and:\n"); 126 PrintStack(rep->stacks[i]); 127 } 128 129 for (uptr i = 0; i < rep->mops.Size(); i++) 130 PrintMop(rep->mops[i], i == 0); 131 132 if (rep->sleep) 133 PrintSleep(rep->sleep); 134 135 for (uptr i = 0; i < rep->locs.Size(); i++) 136 PrintLocation(rep->locs[i]); 137 138 for (uptr i = 0; i < rep->mutexes.Size(); i++) 139 PrintMutex(rep->mutexes[i]); 140 141 for (uptr i = 0; i < rep->threads.Size(); i++) 142 PrintThread(rep->threads[i]); 143 144 TsanPrintf("==================\n"); 145} 146 147#else 148 149void PrintStack(const ReportStack *ent) { 150 for (int i = 0; ent; ent = ent->next, i++) { 151 TsanPrintf(" %s()\n %s:%d +0x%zx\n", 152 ent->func, ent->file, ent->line, (void*)ent->offset); 153 } 154 TsanPrintf("\n"); 155} 156 157static void PrintMop(const ReportMop *mop, bool first) { 158 TsanPrintf("%s by goroutine %d:\n", 159 (first ? (mop->write ? "Write" : "Read") 160 : (mop->write ? "Previous write" : "Previous read")), 161 mop->tid); 162 PrintStack(mop->stack); 163} 164 165static void PrintThread(const ReportThread *rt) { 166 if (rt->id == 0) // Little sense in describing the main thread. 167 return; 168 TsanPrintf("Goroutine %d (%s) created at:\n", 169 rt->id, rt->running ? "running" : "finished"); 170 PrintStack(rt->stack); 171} 172 173void PrintReport(const ReportDesc *rep) { 174 TsanPrintf("==================\n"); 175 TsanPrintf("WARNING: DATA RACE\n"); 176 for (uptr i = 0; i < rep->mops.Size(); i++) 177 PrintMop(rep->mops[i], i == 0); 178 for (uptr i = 0; i < rep->threads.Size(); i++) 179 PrintThread(rep->threads[i]); 180 TsanPrintf("==================\n"); 181} 182 183#endif 184 185} // namespace __tsan 186