tsan_report.cc revision ff35f1d82b4f145b3477ef27a7a2e7b63c486988
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)
247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , threads(MBlockReportThread) {
257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
277ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() {
287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
30c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#ifndef TSAN_GO
31c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintHeader(ReportType typ) {
3367a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("WARNING: ThreadSanitizer: ");
347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
3667a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("data race");
37069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  else if (typ == ReportTypeUseAfterFree)
3867a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("heap-use-after-free");
397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeThreadLeak)
4067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("thread leak");
417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeMutexDestroyLocked)
4267a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("destroy of a locked mutex");
437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else if (typ == ReportTypeSignalUnsafe)
4467a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("signal-unsafe call inside of a signal");
457a72b4a0f04f7f043ab86396b0faa552f55aa857Dmitry Vyukov  else if (typ == ReportTypeErrnoInSignal)
467a72b4a0f04f7f043ab86396b0faa552f55aa857Dmitry Vyukov    TsanPrintf("signal handler spoils errno");
477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4867a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf(" (pid=%d)\n", GetPid());
497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintStack(const ReportStack *ent) {
527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; ent; ent = ent->next, i++) {
5367a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->col)
5567a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov      TsanPrintf(":%d", ent->col);
567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->module && ent->offset)
5767a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov      TsanPrintf(" (%s+%p)\n", ent->module, (void*)ent->offset);
587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
5967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov      TsanPrintf(" (%p)\n", (void*)ent->pc);
607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
61ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  TsanPrintf("\n");
627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) {
6567a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("  %s of size %d at %p",
667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      (first ? (mop->write ? "Write" : "Read")
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany             : (mop->write ? "Previous write" : "Previous read")),
687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      mop->size, (void*)mop->addr);
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (mop->tid == 0)
7067a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" by main thread:\n");
717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else
7267a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" by thread %d:\n", mop->tid);
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(mop->stack);
747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) {
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (loc->type == ReportLocationGlobal) {
78e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    TsanPrintf("  Location is global '%s' of size %zu at %zx %s:%d\n",
7967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov               loc->name, loc->size, loc->addr, loc->file, loc->line);
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationHeap) {
81ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    TsanPrintf("  Location is heap block of size %zu at %p allocated",
82ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov        loc->size, loc->addr);
83ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (loc->tid == 0)
84ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      TsanPrintf(" by main thread:\n");
85ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    else
86ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      TsanPrintf(" by thread %d:\n", loc->tid);
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(loc->stack);
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationStack) {
8967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf("  Location is stack of thread %d:\n", loc->tid);
907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) {
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rm->stack == 0)
957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
9667a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("  Mutex %d created at:\n", rm->id);
977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rm->stack);
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) {
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->id == 0)  // Little sense in describing the main thread.
1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
10367a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("  Thread %d", rt->id);
1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->name)
10567a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" '%s'", rt->name);
10667a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf(" (%s)", rt->running ? "running" : "finished");
1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->stack)
10867a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov    TsanPrintf(" created at:");
10967a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("\n");
1107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rt->stack);
1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) {
11467a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("==================\n");
1157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintHeader(rep->typ);
1167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
117332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  for (uptr i = 0; i < rep->stacks.Size(); i++) {
118332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov    if (i)
119332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov      TsanPrintf("  and:\n");
1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(rep->stacks[i]);
121332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  }
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mops.Size(); i++)
1247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMop(rep->mops[i], i == 0);
1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->locs.Size(); i++)
1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintLocation(rep->locs[i]);
1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mutexes.Size(); i++)
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMutex(rep->mutexes[i]);
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->threads.Size(); i++)
1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintThread(rep->threads[i]);
1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
13567a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov  TsanPrintf("==================\n");
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
138c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#else
139c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
140c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintStack(const ReportStack *ent) {
141c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (int i = 0; ent; ent = ent->next, i++) {
142853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov    TsanPrintf("  %s()\n      %s:%d +0x%zx\n",
143853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov        ent->func, ent->file, ent->line, (void*)ent->offset);
144c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  }
145bbbb20b7212155ebc5b5b4ee1c68c987dcf30320Dmitry Vyukov  TsanPrintf("\n");
146c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
147c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
148c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) {
149c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  TsanPrintf("%s by goroutine %d:\n",
150c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      (first ? (mop->write ? "Write" : "Read")
151c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov             : (mop->write ? "Previous write" : "Previous read")),
152c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      mop->tid);
153c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  PrintStack(mop->stack);
154c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
155c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
15643046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) {
15743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  if (rt->id == 0)  // Little sense in describing the main thread.
15843046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    return;
15943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  TsanPrintf("Goroutine %d (%s) created at:\n",
16043046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    rt->id, rt->running ? "running" : "finished");
16143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  PrintStack(rt->stack);
16243046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov}
16343046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov
164c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) {
165c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  TsanPrintf("==================\n");
166bbbb20b7212155ebc5b5b4ee1c68c987dcf30320Dmitry Vyukov  TsanPrintf("WARNING: DATA RACE\n");
167c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (uptr i = 0; i < rep->mops.Size(); i++)
168c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov    PrintMop(rep->mops[i], i == 0);
16943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  for (uptr i = 0; i < rep->threads.Size(); i++)
17043046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    PrintThread(rep->threads[i]);
171c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  TsanPrintf("==================\n");
172c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
173c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
174c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
175c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
177