tsan_report.cc revision 95f50b126cebecc0165fbf6e4c8209c640836271
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 Printf("WARNING: ThreadSanitizer: "); 35 36 if (typ == ReportTypeRace) 37 Printf("data race"); 38 else if (typ == ReportTypeUseAfterFree) 39 Printf("heap-use-after-free"); 40 else if (typ == ReportTypeThreadLeak) 41 Printf("thread leak"); 42 else if (typ == ReportTypeMutexDestroyLocked) 43 Printf("destroy of a locked mutex"); 44 else if (typ == ReportTypeSignalUnsafe) 45 Printf("signal-unsafe call inside of a signal"); 46 else if (typ == ReportTypeErrnoInSignal) 47 Printf("signal handler spoils errno"); 48 49 Printf(" (pid=%d)\n", GetPid()); 50} 51 52void PrintStack(const ReportStack *ent) { 53 if (ent == 0) { 54 Printf(" [failed to restore the stack]\n\n"); 55 return; 56 } 57 for (int i = 0; ent; ent = ent->next, i++) { 58 Printf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line); 59 if (ent->col) 60 Printf(":%d", ent->col); 61 if (ent->module && ent->offset) 62 Printf(" (%s+%p)\n", ent->module, (void*)ent->offset); 63 else 64 Printf(" (%p)\n", (void*)ent->pc); 65 } 66 Printf("\n"); 67} 68 69static void PrintMop(const ReportMop *mop, bool first) { 70 Printf(" %s of size %d at %p", 71 (first ? (mop->write ? "Write" : "Read") 72 : (mop->write ? "Previous write" : "Previous read")), 73 mop->size, (void*)mop->addr); 74 if (mop->tid == 0) 75 Printf(" by main thread:\n"); 76 else 77 Printf(" by thread %d:\n", mop->tid); 78 PrintStack(mop->stack); 79} 80 81static void PrintLocation(const ReportLocation *loc) { 82 if (loc->type == ReportLocationGlobal) { 83 Printf(" Location is global '%s' of size %zu at %zx %s:%d\n", 84 loc->name, loc->size, loc->addr, loc->file, loc->line); 85 } else if (loc->type == ReportLocationHeap) { 86 Printf(" Location is heap block of size %zu at %p allocated", 87 loc->size, loc->addr); 88 if (loc->tid == 0) 89 Printf(" by main thread:\n"); 90 else 91 Printf(" by thread %d:\n", loc->tid); 92 PrintStack(loc->stack); 93 } else if (loc->type == ReportLocationStack) { 94 Printf(" Location is stack of thread %d:\n", loc->tid); 95 } 96} 97 98static void PrintMutex(const ReportMutex *rm) { 99 if (rm->stack == 0) 100 return; 101 Printf(" Mutex %d created at:\n", rm->id); 102 PrintStack(rm->stack); 103} 104 105static void PrintThread(const ReportThread *rt) { 106 if (rt->id == 0) // Little sense in describing the main thread. 107 return; 108 Printf(" Thread %d", rt->id); 109 if (rt->name) 110 Printf(" '%s'", rt->name); 111 Printf(" (tid=%zu, %s)", rt->pid, rt->running ? "running" : "finished"); 112 if (rt->stack) 113 Printf(" created at:"); 114 Printf("\n"); 115 PrintStack(rt->stack); 116} 117 118static void PrintSleep(const ReportStack *s) { 119 Printf(" As if synchronized via sleep:\n"); 120 PrintStack(s); 121} 122 123void PrintReport(const ReportDesc *rep) { 124 Printf("==================\n"); 125 PrintHeader(rep->typ); 126 127 for (uptr i = 0; i < rep->stacks.Size(); i++) { 128 if (i) 129 Printf(" and:\n"); 130 PrintStack(rep->stacks[i]); 131 } 132 133 for (uptr i = 0; i < rep->mops.Size(); i++) 134 PrintMop(rep->mops[i], i == 0); 135 136 if (rep->sleep) 137 PrintSleep(rep->sleep); 138 139 for (uptr i = 0; i < rep->locs.Size(); i++) 140 PrintLocation(rep->locs[i]); 141 142 for (uptr i = 0; i < rep->mutexes.Size(); i++) 143 PrintMutex(rep->mutexes[i]); 144 145 for (uptr i = 0; i < rep->threads.Size(); i++) 146 PrintThread(rep->threads[i]); 147 148 Printf("==================\n"); 149} 150 151#else 152 153void PrintStack(const ReportStack *ent) { 154 for (int i = 0; ent; ent = ent->next, i++) { 155 Printf(" %s()\n %s:%d +0x%zx\n", 156 ent->func, ent->file, ent->line, (void*)ent->offset); 157 } 158 Printf("\n"); 159} 160 161static void PrintMop(const ReportMop *mop, bool first) { 162 Printf("%s by goroutine %d:\n", 163 (first ? (mop->write ? "Write" : "Read") 164 : (mop->write ? "Previous write" : "Previous read")), 165 mop->tid); 166 PrintStack(mop->stack); 167} 168 169static void PrintThread(const ReportThread *rt) { 170 if (rt->id == 0) // Little sense in describing the main thread. 171 return; 172 Printf("Goroutine %d (%s) created at:\n", 173 rt->id, rt->running ? "running" : "finished"); 174 PrintStack(rt->stack); 175} 176 177void PrintReport(const ReportDesc *rep) { 178 Printf("==================\n"); 179 Printf("WARNING: DATA RACE\n"); 180 for (uptr i = 0; i < rep->mops.Size(); i++) 181 PrintMop(rep->mops[i], i == 0); 182 for (uptr i = 0; i < rep->threads.Size(); i++) 183 PrintThread(rep->threads[i]); 184 Printf("==================\n"); 185} 186 187#endif 188 189} // namespace __tsan 190