]> git.ipfire.org Git - thirdparty/gcc.git/blob - libsanitizer/tsan/tsan_report.cc
[libsanitizer] merge from upstream r169371
[thirdparty/gcc.git] / libsanitizer / tsan / tsan_report.cc
1 //===-- tsan_report.cc ----------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
9 //
10 //===----------------------------------------------------------------------===//
11 #include "tsan_report.h"
12 #include "tsan_platform.h"
13 #include "tsan_rtl.h"
14
15 namespace __tsan {
16
17 ReportDesc::ReportDesc()
18 : stacks(MBlockReportStack)
19 , mops(MBlockReportMop)
20 , locs(MBlockReportLoc)
21 , mutexes(MBlockReportMutex)
22 , threads(MBlockReportThread)
23 , sleep() {
24 }
25
26 ReportDesc::~ReportDesc() {
27 // FIXME(dvyukov): it must be leaking a lot of memory.
28 }
29
30 #ifndef TSAN_GO
31
32 static void PrintHeader(ReportType typ) {
33 Printf("WARNING: ThreadSanitizer: ");
34
35 if (typ == ReportTypeRace)
36 Printf("data race");
37 else if (typ == ReportTypeUseAfterFree)
38 Printf("heap-use-after-free");
39 else if (typ == ReportTypeThreadLeak)
40 Printf("thread leak");
41 else if (typ == ReportTypeMutexDestroyLocked)
42 Printf("destroy of a locked mutex");
43 else if (typ == ReportTypeSignalUnsafe)
44 Printf("signal-unsafe call inside of a signal");
45 else if (typ == ReportTypeErrnoInSignal)
46 Printf("signal handler spoils errno");
47
48 Printf(" (pid=%d)\n", GetPid());
49 }
50
51 void PrintStack(const ReportStack *ent) {
52 if (ent == 0) {
53 Printf(" [failed to restore the stack]\n\n");
54 return;
55 }
56 for (int i = 0; ent; ent = ent->next, i++) {
57 Printf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line);
58 if (ent->col)
59 Printf(":%d", ent->col);
60 if (ent->module && ent->offset)
61 Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
62 else
63 Printf(" (%p)\n", (void*)ent->pc);
64 }
65 Printf("\n");
66 }
67
68 static void PrintMop(const ReportMop *mop, bool first) {
69 Printf(" %s of size %d at %p",
70 (first ? (mop->write ? "Write" : "Read")
71 : (mop->write ? "Previous write" : "Previous read")),
72 mop->size, (void*)mop->addr);
73 if (mop->tid == 0)
74 Printf(" by main thread:\n");
75 else
76 Printf(" by thread %d:\n", mop->tid);
77 PrintStack(mop->stack);
78 }
79
80 static void PrintLocation(const ReportLocation *loc) {
81 if (loc->type == ReportLocationGlobal) {
82 Printf(" Location is global '%s' of size %zu at %zx %s:%d (%s+%p)\n\n",
83 loc->name, loc->size, loc->addr, loc->file, loc->line,
84 loc->module, loc->offset);
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\n", loc->tid);
95 }
96 }
97
98 static 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
105 static 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
118 static void PrintSleep(const ReportStack *s) {
119 Printf(" As if synchronized via sleep:\n");
120 PrintStack(s);
121 }
122
123 void 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
153 void PrintStack(const ReportStack *ent) {
154 if (ent == 0) {
155 Printf(" [failed to restore the stack]\n\n");
156 return;
157 }
158 for (int i = 0; ent; ent = ent->next, i++) {
159 Printf(" %s()\n %s:%d +0x%zx\n",
160 ent->func, ent->file, ent->line, (void*)ent->offset);
161 }
162 Printf("\n");
163 }
164
165 static void PrintMop(const ReportMop *mop, bool first) {
166 Printf("%s by goroutine %d:\n",
167 (first ? (mop->write ? "Write" : "Read")
168 : (mop->write ? "Previous write" : "Previous read")),
169 mop->tid);
170 PrintStack(mop->stack);
171 }
172
173 static void PrintThread(const ReportThread *rt) {
174 if (rt->id == 0) // Little sense in describing the main thread.
175 return;
176 Printf("Goroutine %d (%s) created at:\n",
177 rt->id, rt->running ? "running" : "finished");
178 PrintStack(rt->stack);
179 }
180
181 void PrintReport(const ReportDesc *rep) {
182 Printf("==================\n");
183 Printf("WARNING: DATA RACE\n");
184 for (uptr i = 0; i < rep->mops.Size(); i++)
185 PrintMop(rep->mops[i], i == 0);
186 for (uptr i = 0; i < rep->threads.Size(); i++)
187 PrintThread(rep->threads[i]);
188 Printf("==================\n");
189 }
190
191 #endif
192
193 } // namespace __tsan