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