• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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