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
17 namespace __tsan {
18
ReportDesc()19 ReportDesc::ReportDesc()
20 : stacks(MBlockReportStack)
21 , mops(MBlockReportMop)
22 , locs(MBlockReportLoc)
23 , mutexes(MBlockReportMutex)
24 , threads(MBlockReportThread)
25 , sleep() {
26 }
27
~ReportDesc()28 ReportDesc::~ReportDesc() {
29 }
30
31 #ifndef TSAN_GO
32
PrintHeader(ReportType typ)33 static 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
PrintStack(const ReportStack * ent)52 void 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
PrintMop(const ReportMop * mop,bool first)65 static 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
PrintLocation(const ReportLocation * loc)77 static 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
PrintMutex(const ReportMutex * rm)94 static 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
PrintThread(const ReportThread * rt)101 static 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
PrintSleep(const ReportStack * s)114 static void PrintSleep(const ReportStack *s) {
115 TsanPrintf(" As if synchronized via sleep:\n");
116 PrintStack(s);
117 }
118
PrintReport(const ReportDesc * rep)119 void 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
PrintStack(const ReportStack * ent)149 void 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
PrintMop(const ReportMop * mop,bool first)157 static 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
PrintThread(const ReportThread * rt)165 static 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
PrintReport(const ReportDesc * rep)173 void 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