tsan_report.cc revision 0ab628c61594eb80612e5389d9c33da0e0d70c66
1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_report.cc ----------------------------------------------------===//
27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//                     The LLVM Compiler Infrastructure
47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source
67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details.
77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector.
117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_report.h"
147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h"
157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
197ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::ReportDesc()
207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : stacks(MBlockReportStack)
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mops(MBlockReportMop)
227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , locs(MBlockReportLoc)
237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mutexes(MBlockReportMutex)
24848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , threads(MBlockReportThread)
25848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , sleep() {
267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
287ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() {
297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
31c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#ifndef TSAN_GO
32c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintHeader(ReportType typ) {
3467a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("WARNING: ThreadSanitizer: ");
357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
3767a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("data race");
38069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  else if (typ == ReportTypeUseAfterFree)
3967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("heap-use-after-free");
407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeThreadLeak)
4167a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("thread leak");
427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeMutexDestroyLocked)
4367a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("destroy of a locked mutex");
447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeSignalUnsafe)
4567a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("signal-unsafe call inside of a signal");
467a72b4a0f04f7f043ab86396b0faa552f55aa857Dmitry Vyukov  else if (typ == ReportTypeErrnoInSignal)
477a72b4a0f04f7f043ab86396b0faa552f55aa857Dmitry Vyukov    TsanPrintf("signal handler spoils errno");
487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf(" (pid=%d)\n", GetPid());
507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
521da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintStack(const ReportStack *ent) {
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; ent; ent = ent->next, i++) {
5467a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->col)
5667a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov      TsanPrintf(":%d", ent->col);
577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->module && ent->offset)
5867a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov      TsanPrintf(" (%s+%p)\n", ent->module, (void*)ent->offset);
597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
6067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov      TsanPrintf(" (%p)\n", (void*)ent->pc);
617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
62ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  TsanPrintf("\n");
637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) {
6667a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("  %s of size %d at %p",
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      (first ? (mop->write ? "Write" : "Read")
687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany             : (mop->write ? "Previous write" : "Previous read")),
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      mop->size, (void*)mop->addr);
707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (mop->tid == 0)
7167a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" by main thread:\n");
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else
7367a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" by thread %d:\n", mop->tid);
747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(mop->stack);
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) {
787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (loc->type == ReportLocationGlobal) {
79e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    TsanPrintf("  Location is global '%s' of size %zu at %zx %s:%d\n",
8067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov               loc->name, loc->size, loc->addr, loc->file, loc->line);
817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationHeap) {
82ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    TsanPrintf("  Location is heap block of size %zu at %p allocated",
83ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov        loc->size, loc->addr);
84ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (loc->tid == 0)
85ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      TsanPrintf(" by main thread:\n");
86ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    else
87ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      TsanPrintf(" by thread %d:\n", loc->tid);
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(loc->stack);
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationStack) {
9067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("  Location is stack of thread %d:\n", loc->tid);
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) {
957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rm->stack == 0)
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
9767a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("  Mutex %d created at:\n", rm->id);
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rm->stack);
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) {
1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->id == 0)  // Little sense in describing the main thread.
1037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
10467a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("  Thread %d", rt->id);
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->name)
10667a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" '%s'", rt->name);
10767a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf(" (%s)", rt->running ? "running" : "finished");
1087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->stack)
10967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" created at:");
11067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("\n");
1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rt->stack);
1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
114848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovstatic void PrintSleep(const ReportStack *s) {
115848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  TsanPrintf("  As if synchronized via sleep:\n");
116848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  PrintStack(s);
117848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
118848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
1197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) {
12067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("==================\n");
1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintHeader(rep->typ);
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
123332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  for (uptr i = 0; i < rep->stacks.Size(); i++) {
124332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov    if (i)
125332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov      TsanPrintf("  and:\n");
1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(rep->stacks[i]);
127332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  }
1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mops.Size(); i++)
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMop(rep->mops[i], i == 0);
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
132848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (rep->sleep)
133848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    PrintSleep(rep->sleep);
134848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->locs.Size(); i++)
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintLocation(rep->locs[i]);
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mutexes.Size(); i++)
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMutex(rep->mutexes[i]);
1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->threads.Size(); i++)
1427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintThread(rep->threads[i]);
1437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
14467a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("==================\n");
1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
147c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#else
148c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
1490ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukovvoid PrintStack(const ReportStack *ent) {
150c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (int i = 0; ent; ent = ent->next, i++) {
151853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov    TsanPrintf("  %s()\n      %s:%d +0x%zx\n",
152853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov        ent->func, ent->file, ent->line, (void*)ent->offset);
153c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  }
154bbbb20b7212155ebc5b5b4ee1c68c987dcf30320Dmitry Vyukov  TsanPrintf("\n");
155c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
156c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
157c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) {
158c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  TsanPrintf("%s by goroutine %d:\n",
159c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      (first ? (mop->write ? "Write" : "Read")
160c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov             : (mop->write ? "Previous write" : "Previous read")),
161c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      mop->tid);
162c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  PrintStack(mop->stack);
163c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
164c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
16543046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) {
16643046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  if (rt->id == 0)  // Little sense in describing the main thread.
16743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    return;
16843046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  TsanPrintf("Goroutine %d (%s) created at:\n",
16943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    rt->id, rt->running ? "running" : "finished");
17043046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  PrintStack(rt->stack);
17143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov}
17243046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov
173c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) {
174c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  TsanPrintf("==================\n");
175bbbb20b7212155ebc5b5b4ee1c68c987dcf30320Dmitry Vyukov  TsanPrintf("WARNING: DATA RACE\n");
176c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (uptr i = 0; i < rep->mops.Size(); i++)
177c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov    PrintMop(rep->mops[i], i == 0);
17843046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  for (uptr i = 0; i < rep->threads.Size(); i++)
17943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    PrintThread(rep->threads[i]);
180c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  TsanPrintf("==================\n");
181c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
182c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
183c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
184c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
1857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
186