16fbecdd97512bd7d9ccef130e99650d446b50444Alexey Samsonov//===-- tsan_rtl_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
14c0d78c1de1f2607c874020d27b72cf989c5ce092Alexey Samsonov#include "sanitizer_common/sanitizer_libc.h"
1547b1634df012507799eb39aa17d4022d748ba67bAlexey Samsonov#include "sanitizer_common/sanitizer_placement_new.h"
16ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov#include "sanitizer_common/sanitizer_stackdepot.h"
17ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov#include "sanitizer_common/sanitizer_common.h"
18793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov#include "sanitizer_common/sanitizer_stacktrace.h"
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h"
207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_suppressions.h"
227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_symbolize.h"
237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_report.h"
247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_sync.h"
257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h"
267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_flags.h"
27c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov#include "tsan_fd.h"
287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
29591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovnamespace __tsan {
3015a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
31ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovusing namespace __sanitizer;  // NOLINT
32ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
336d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic ReportStack *SymbolizeStack(StackTrace trace);
34793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov
35591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovvoid TsanCheckFailed(const char *file, int line, const char *cond,
36591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov                     u64 v1, u64 v2) {
372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // There is high probability that interceptors will check-fail as well,
382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // on the other hand there is no sense in processing interceptors
392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // since we are going to die soon.
402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ScopedIgnoreInterceptors ignore;
41b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("FATAL: ThreadSanitizer CHECK failed: "
42b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov         "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
43b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov         file, line, cond, (uptr)v1, (uptr)v2);
446d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
4515a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  Die();
4615a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov}
4715a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// Can be overriden by an application/test to intercept reports.
4987dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov#ifdef TSAN_EXTERNAL_HOOKS
5087dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukovbool OnReport(const ReportDesc *rep, bool suppressed);
5187dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov#else
529a46c3b7aeb3a800702b48dd5f8017b0ae7387c7Alexey SamsonovSANITIZER_INTERFACE_ATTRIBUTE
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanybool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  (void)rep;
557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return suppressed;
567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5787dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov#endif
587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5986277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic void StackStripMain(SymbolizedStack *frames) {
6086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SymbolizedStack *last_frame = nullptr;
6186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SymbolizedStack *last_frame2 = nullptr;
6286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2 = last_frame;
6486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame = cur;
657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (last_frame2 == 0)
687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
6986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
706d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  const char *last = last_frame->info.function;
716d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  const char *last2 = last_frame2->info.function;
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip frame above 'main'
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (last2 && 0 == internal_strcmp(last2, "main")) {
7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame->ClearAll();
7586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame2->next = nullptr;
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip our internal thread start routine.
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) {
7886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame->ClearAll();
7986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame2->next = nullptr;
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip global ctors init.
817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) {
8286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame->ClearAll();
8386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last_frame2->next = nullptr;
847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // If both are 0, then we probably just failed to symbolize.
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last || last2) {
867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // Ensure that we recovered stack completely. Trimmed stack
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // can actually happen if we do not instrument some code,
880ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    // so it's only a debug print. However we must try hard to not miss it
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // due to our fault.
9086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    DPrintf("Bottom stack frame is missed\n");
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
92cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#else
931dc5f39fbcb09734809b73eb16dd64b50d647038Dmitry Vyukov  // The last frame always point into runtime (gosched0, goexit0, runtime.main).
9486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  last_frame->ClearAll();
9586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  last_frame2->next = nullptr;
96c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesReportStack *SymbolizeStackId(u32 stack_id) {
1002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (stack_id == 0)
1012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
1026d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  StackTrace stack = StackDepotGet(stack_id);
1036d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (stack.trace == nullptr)
1046d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return nullptr;
1056d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return SymbolizeStack(stack);
1062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1086d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic ReportStack *SymbolizeStack(StackTrace trace) {
1096d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (trace.size == 0)
1107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return 0;
11186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SymbolizedStack *top = nullptr;
1126d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  for (uptr si = 0; si < trace.size; si++) {
1136d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    const uptr pc = trace.trace[si];
114e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    uptr pc1 = pc;
11586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    // We obtain the return address, but we're interested in the previous
11686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    // instruction.
11786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    if ((pc & kExternalPCBit) == 0)
11886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      pc1 = StackTrace::GetPreviousInstructionPc(pc);
11986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    SymbolizedStack *ent = SymbolizeCode(pc1);
1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK_NE(ent, 0);
12186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    SymbolizedStack *last = ent;
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (last->next) {
1236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      last->info.address = pc;  // restore original pc for report
1247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      last = last->next;
1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1266d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    last->info.address = pc;  // restore original pc for report
12786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    last->next = top;
12886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    top = ent;
1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
13086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  StackStripMain(top);
13186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
13286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  ReportStack *stack = ReportStack::New();
13386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  stack->frames = top;
1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return stack;
1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1377ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::ScopedReport(ReportType typ) {
1382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->thread_registry->CheckLocked();
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_ = new(mem) ReportDesc;
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->typ = typ;
1422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->report_mtx.Lock();
1437ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov  CommonSanitizerReportMutex.Lock();
1447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1467ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::~ScopedReport() {
1477ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov  CommonSanitizerReportMutex.Unlock();
1482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->report_mtx.Unlock();
149aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  DestroyAndFree(rep_);
1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1526d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid ScopedReport::AddStack(StackTrace stack, bool suppressable) {
1537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack **rs = rep_->stacks.PushBack();
1546d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  *rs = SymbolizeStack(stack);
1556a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  (*rs)->suppressable = suppressable;
1567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1586d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
1596d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                                   const MutexSet *mset) {
1607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
1617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportMop *mop = new(mem) ReportMop;
1627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->mops.PushBack(mop);
1637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->tid = s.tid();
1647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->addr = addr + s.addr0();
1657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->size = s.size();
166334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov  mop->write = s.IsWrite();
1670a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  mop->atomic = s.IsAtomic();
1686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  mop->stack = SymbolizeStack(stack);
1696a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (mop->stack)
1706a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    mop->stack->suppressable = true;
171ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset->Size(); i++) {
172ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    MutexSet::Desc d = mset->Get(i);
1732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    u64 mid = this->AddMutex(d.id);
1742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ReportMopMutex mtx = {mid, d.write};
1752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    mop->mset.PushBack(mtx);
176ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
1777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ScopedReport::AddUniqueTid(int unique_tid) {
1802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rep_->unique_tids.PushBack(unique_tid);
1812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1836a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesvoid ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
184ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  for (uptr i = 0; i < rep_->threads.Size(); i++) {
1852bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    if ((u32)rep_->threads[i]->id == tctx->tid)
186ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      return;
187ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportThread *rt = new(mem) ReportThread();
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->threads.PushBack(rt);
1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->id = tctx->tid;
1927dccf3f92a867f917ad19f9a6b37bcf93e64b35bDmitry Vyukov  rt->pid = tctx->os_id;
1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->running = (tctx->status == ThreadStatusRunning);
1942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rt->name = internal_strdup(tctx->name);
1952bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  rt->parent_tid = tctx->parent_tid;
1962c5284e0f87e101e177a151fae5f557bcf6f664cDmitry Vyukov  rt->stack = 0;
1972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rt->stack = SymbolizeStackId(tctx->creation_stack_id);
1986a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (rt->stack)
1996a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    rt->stack->suppressable = suppressable;
2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
20286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
203df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonovstatic ThreadContext *FindThreadByUidLocked(int unique_id) {
2042bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ctx->thread_registry->CheckLocked();
205ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  for (unsigned i = 0; i < kMaxTid; i++) {
2062bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    ThreadContext *tctx = static_cast<ThreadContext*>(
2072bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov        ctx->thread_registry->GetThreadLocked(i));
2082bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    if (tctx && tctx->unique_id == (u32)unique_id) {
209ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      return tctx;
210ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    }
211ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
212ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  return 0;
213ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov}
214fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov
215f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukovstatic ThreadContext *FindThreadByTidLocked(int tid) {
216f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov  ctx->thread_registry->CheckLocked();
217f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov  return static_cast<ThreadContext*>(
218f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov      ctx->thread_registry->GetThreadLocked(tid));
219f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov}
220f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov
221df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonovstatic bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) {
222df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  uptr addr = (uptr)arg;
223df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
224df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  if (tctx->status != ThreadStatusRunning)
225df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov    return false;
226df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadState *thr = tctx->thr;
227df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  CHECK(thr);
228df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  return ((addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) ||
229df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov          (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size));
230df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov}
231df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov
232fb917e9069ea44f7103f50c658be84a8f66de56cDmitry VyukovThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
2332bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ctx->thread_registry->CheckLocked();
234df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadContext *tctx = static_cast<ThreadContext*>(
235df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov      ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls,
236df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov                                                    (void*)addr));
237df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  if (!tctx)
238df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov    return 0;
239df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadState *thr = tctx->thr;
240df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  CHECK(thr);
241df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  *is_stack = (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size);
242df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  return tctx;
243fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov}
2440ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
245ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov
2466a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesvoid ScopedReport::AddThread(int unique_tid, bool suppressable) {
24786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
24886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid))
24986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    AddThread(tctx, suppressable);
2502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif
2512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
2522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
2537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMutex(const SyncVar *s) {
254ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
255ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (rep_->mutexes[i]->id == s->uid)
256ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      return;
257ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
2587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
2597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportMutex *rm = new(mem) ReportMutex();
2607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->mutexes.PushBack(rm);
261ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->id = s->uid;
2622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rm->addr = s->addr;
263ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->destroyed = false;
2642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rm->stack = SymbolizeStackId(s->creation_stack_id);
2652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
2662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
2672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesu64 ScopedReport::AddMutex(u64 id) {
2682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  u64 uid = 0;
2692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  u64 mid = id;
2702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr addr = SyncVar::SplitId(id, &uid);
2716a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
2722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Check that the mutex is still alive.
2732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Another mutex can be created at the same address,
2742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // so check uid as well.
2752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (s && s->CheckId(uid)) {
2762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    mid = s->uid;
2772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    AddMutex(s);
2782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  } else {
2792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    AddDeadMutex(id);
2802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
2812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (s)
2826a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    s->mtx.Unlock();
2832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return mid;
2847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ScopedReport::AddDeadMutex(u64 id) {
287ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
288ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (rep_->mutexes[i]->id == id)
289ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      return;
290ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
291ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
292ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  ReportMutex *rm = new(mem) ReportMutex();
293ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rep_->mutexes.PushBack(rm);
294ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->id = id;
2952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rm->addr = 0;
296ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->destroyed = true;
297ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->stack = 0;
298ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
299ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
3007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddLocation(uptr addr, uptr size) {
301ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  if (addr == 0)
302ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
30386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
304c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  int fd = -1;
305c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  int creat_tid = -1;
306c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  u32 creat_stack = 0;
3076d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) {
3086d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    ReportLocation *loc = ReportLocation::New(ReportLocationFD);
309c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->fd = fd;
310c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->tid = creat_tid;
3112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    loc->stack = SymbolizeStackId(creat_stack);
3126d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    rep_->locs.PushBack(loc);
313df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov    ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
314c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    if (tctx)
315c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      AddThread(tctx);
316c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    return;
317c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  }
31803049413f8978c202a254eb0acfa2f10b9bbe34aDmitry Vyukov  MBlock *b = 0;
3196a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  Allocator *a = allocator();
3206a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (a->PointerIsMine((void*)addr)) {
3216a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    void *block_begin = a->GetBlockBegin((void*)addr);
3226a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    if (block_begin)
3236a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines      b = ctx->metamap.GetBlock((uptr)block_begin);
3246a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  }
3256a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (b != 0) {
3266a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    ThreadContext *tctx = FindThreadByTidLocked(b->tid);
3276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
3286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
3296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    loc->heap_chunk_size = b->siz;
3306a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    loc->tid = tctx ? tctx->tid : b->tid;
3316a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    loc->stack = SymbolizeStackId(b->stk);
3326d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    rep_->locs.PushBack(loc);
333ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (tctx)
334ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      AddThread(tctx);
335ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
336ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
337fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  bool is_stack = false;
338fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
3396d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    ReportLocation *loc =
3406d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS);
341fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    loc->tid = tctx->tid;
3426d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    rep_->locs.PushBack(loc);
343fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    AddThread(tctx);
344fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  }
3456d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (ReportLocation *loc = SymbolizeData(addr)) {
3466a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    loc->suppressable = true;
3477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    rep_->locs.PushBack(loc);
348ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
3497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
350fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov#endif
3517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
35386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
354848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovvoid ScopedReport::AddSleep(u32 stack_id) {
3552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rep_->sleep = SymbolizeStackId(stack_id);
356848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
3570ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
358848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
3594536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukovvoid ScopedReport::SetCount(int count) {
3604536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov  rep_->count = count;
3614536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov}
3624536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov
3637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst ReportDesc *ScopedReport::GetReport() const {
3647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return rep_;
3657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3676d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
3686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                  MutexSet *mset) {
369ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // This function restores stack trace and mutex set for the thread/epoch.
370ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // It does so by getting stack trace and mutex set at the beginning of
371ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // trace part, and then replaying the trace till the given epoch.
3722bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ctx->thread_registry->CheckLocked();
3732bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ThreadContext *tctx = static_cast<ThreadContext*>(
3742bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov      ctx->thread_registry->GetThreadLocked(tid));
3757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (tctx == 0)
3767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
3779743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  if (tctx->status != ThreadStatusRunning
3789743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov      && tctx->status != ThreadStatusFinished
3799743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov      && tctx->status != ThreadStatusDead)
3807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
3819743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  Trace* trace = ThreadTrace(tctx->tid);
3827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Lock l(&trace->mtx);
3830415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  const int partidx = (epoch / kTracePartSize) % TraceParts();
3847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  TraceHeader* hdr = &trace->headers[partidx];
3857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (epoch < hdr->epoch0)
3867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
387ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  const u64 epoch0 = RoundDown(epoch, TraceSize());
388d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov  const u64 eend = epoch % TraceSize();
3890415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  const u64 ebegin = RoundDown(eend, kTracePartSize);
390e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov  DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
391e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov          tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
39201a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov  InternalScopedBuffer<uptr> stack(kShadowStackSize);
3936d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  for (uptr i = 0; i < hdr->stack0.size; i++) {
3946d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    stack[i] = hdr->stack0.trace[i];
39586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    DPrintf2("  #%02zu: pc=%zx\n", i, stack[i]);
3967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
397ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (mset)
398ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    *mset = hdr->mset0;
3996d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  uptr pos = hdr->stack0.size;
400385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  Event *events = (Event*)GetThreadTrace(tid);
4017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = ebegin; i <= eend; i++) {
402385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov    Event ev = events[i];
4037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    EventType typ = (EventType)(ev >> 61);
404ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    uptr pc = (uptr)(ev & ((1ull << 61) - 1));
405e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    DPrintf2("  %zu typ=%d pc=%zx\n", i, typ, pc);
4067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (typ == EventTypeMop) {
4077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      stack[pos] = pc;
4087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    } else if (typ == EventTypeFuncEnter) {
4097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      stack[pos++] = pc;
4107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    } else if (typ == EventTypeFuncExit) {
4117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (pos > 0)
4127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        pos--;
4137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
414ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (mset) {
415ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      if (typ == EventTypeLock) {
416ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Add(pc, true, epoch0 + i);
417ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeUnlock) {
418ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Del(pc, true);
419ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeRLock) {
420ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Add(pc, false, epoch0 + i);
421ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeRUnlock) {
422ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Del(pc, false);
423ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      }
424ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    }
4257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr j = 0; j <= pos; j++)
426e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov      DPrintf2("      #%zu: %zx\n", j, stack[j]);
4277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (pos == 0 && stack[0] == 0)
4297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
4307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  pos++;
4311dc4cf7e253aefa3ce3bd4a1d349a13647e8b2eaAlexey Samsonov  stk->Init(stack.data(), pos);
4327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4346d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
4356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                             uptr addr_min, uptr addr_max) {
4367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool equal_stack = false;
437e0c45610e138c9e0b518189b7fa286f4b7ee6474Dmitry Vyukov  RacyStacks hash;
4387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_stacks) {
4396d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
4406d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
4417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
4427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (hash == ctx->racy_stacks[i]) {
4437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
4447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        equal_stack = true;
4457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
4467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
4477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
4487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool equal_address = false;
4507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  RacyAddress ra0 = {addr_min, addr_max};
4517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_addresses) {
4527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
4537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      RacyAddress ra2 = ctx->racy_addresses[i];
4547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
4557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      uptr minend = min(ra0.addr_max, ra2.addr_max);
4567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (maxbeg < minend) {
4577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n");
4587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        equal_address = true;
4597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
4607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
4617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
4627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (equal_stack || equal_address) {
4647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (!equal_stack)
4657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ctx->racy_stacks.PushBack(hash);
4667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (!equal_address)
4677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ctx->racy_addresses.PushBack(ra0);
4687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return true;
4697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return false;
4717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4736d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
4746d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                          uptr addr_min, uptr addr_max) {
4757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_stacks) {
476e0c45610e138c9e0b518189b7fa286f4b7ee6474Dmitry Vyukov    RacyStacks hash;
4776d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
4786d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
4797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ctx->racy_stacks.PushBack(hash);
4807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_addresses) {
4827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    RacyAddress ra0 = {addr_min, addr_max};
4837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ctx->racy_addresses.PushBack(ra0);
4847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4876a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesbool OutputReport(ThreadState *thr, const ScopedReport &srep) {
488a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov  atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
4897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const ReportDesc *rep = srep.GetReport();
490f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov  Suppression *supp = 0;
4916a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  uptr suppress_pc = 0;
4926a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++)
4936a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
4946a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++)
4956a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp);
4966a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++)
4976a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
4986a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++)
4996a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp);
500158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (suppress_pc != 0) {
501f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov    FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
5020a05e5fa28a7424f8146549057c53b4590f3a251Alexey Samsonov    ctx->fired_suppressions.push_back(s);
503158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  }
5046a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  {
5056a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    bool old_is_freeing = thr->is_freeing;
5066a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    thr->is_freeing = false;
5076a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    bool suppressed = OnReport(rep, suppress_pc != 0);
5086a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    thr->is_freeing = old_is_freeing;
5096a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    if (suppressed)
5106a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines      return false;
5116a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  }
5127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintReport(rep);
513dbac0a4a41f405d10e3dcad3597fe08986605289Dmitry Vyukov  ctx->nreported++;
514dbac0a4a41f405d10e3dcad3597fe08986605289Dmitry Vyukov  if (flags()->halt_on_error)
515dbac0a4a41f405d10e3dcad3597fe08986605289Dmitry Vyukov    internal__exit(flags()->exitcode);
5167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return true;
5177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5196d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesbool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
5206d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                        StackTrace trace) {
5210a05e5fa28a7424f8146549057c53b4590f3a251Alexey Samsonov  for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
522158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
523158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov      continue;
5246d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    for (uptr j = 0; j < trace.size; j++) {
525f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov      FiredSuppression *s = &ctx->fired_suppressions[k];
5266d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      if (trace.trace[j] == s->pc) {
527f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov        if (s->supp)
528f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov          s->supp->hit_count++;
529158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov        return true;
530f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov      }
531158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    }
532158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  }
533158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  return false;
534158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov}
535158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov
53639968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukovstatic bool IsFiredSuppression(Context *ctx,
53739968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov                               const ScopedReport &srep,
53839968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov                               uptr addr) {
5390a05e5fa28a7424f8146549057c53b4590f3a251Alexey Samsonov  for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
54039968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
54139968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov      continue;
54239968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    FiredSuppression *s = &ctx->fired_suppressions[k];
54339968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    if (addr == s->pc) {
54439968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov      if (s->supp)
54539968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov        s->supp->hit_count++;
54639968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov      return true;
54739968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    }
54839968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  }
54939968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  return false;
55039968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov}
55139968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov
5523285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukovstatic bool RaceBetweenAtomicAndFree(ThreadState *thr) {
5533285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  Shadow s0(thr->racy_state[0]);
5543285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  Shadow s1(thr->racy_state[1]);
5553285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
5563285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (!s0.IsAtomic() && !s1.IsAtomic())
5573285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
5583285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (s0.IsAtomic() && s1.IsFreed())
5593285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
5603285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (s1.IsAtomic() && thr->is_freeing)
5613285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
5623285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  return false;
5633285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov}
5643285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov
5657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ReportRace(ThreadState *thr) {
5666a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  CheckNoLocks(thr);
5676a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines
5682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Symbolizer makes lots of intercepted calls. If we try to process them,
5692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // at best it will cause deadlocks on internal mutexes.
5702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ScopedIgnoreInterceptors ignore;
5712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
5728a326776e41dc68c810ba3719a24328de517d8f9Dmitry Vyukov  if (!flags()->report_bugs)
5738a326776e41dc68c810ba3719a24328de517d8f9Dmitry Vyukov    return;
5743285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
5753285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return;
5763285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov
577069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  bool freed = false;
578069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  {
579069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    Shadow s(thr->racy_state[1]);
580069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    freed = s.GetFreedAndReset();
581069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    thr->racy_state[1] = s.raw();
582069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  }
583069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov
5847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr);
5857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr_min = 0;
5867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr_max = 0;
5877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
5887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr a0 = addr + Shadow(thr->racy_state[0]).addr0();
5897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr a1 = addr + Shadow(thr->racy_state[1]).addr0();
5907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr e0 = a0 + Shadow(thr->racy_state[0]).size();
5917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr e1 = a1 + Shadow(thr->racy_state[1]).size();
5927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr_min = min(a0, a1);
5937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr_max = max(e0, e1);
5947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (IsExpectedReport(addr_min, addr_max - addr_min))
5957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      return;
5967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
5977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5982bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ThreadRegistryLock l0(ctx->thread_registry);
5997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6000dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  ReportType typ = ReportTypeRace;
6016d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (thr->is_vptr_access && freed)
6026d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    typ = ReportTypeVptrUseAfterFree;
6036d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  else if (thr->is_vptr_access)
6040dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    typ = ReportTypeVptrRace;
6050dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  else if (freed)
6060dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    typ = ReportTypeUseAfterFree;
6070dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  ScopedReport rep(typ);
60839968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  if (IsFiredSuppression(ctx, rep, addr))
60939968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    return;
610069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  const uptr kMop = 2;
6116d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  VarSizeStackTrace traces[kMop];
612385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  const uptr toppc = TraceTopPC(thr);
6136d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  ObtainCurrentStack(thr, toppc, &traces[0]);
614158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (IsFiredSuppression(ctx, rep, traces[0]))
615158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    return;
616ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  InternalScopedBuffer<MutexSet> mset2(1);
617ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  new(mset2.data()) MutexSet();
618158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  Shadow s2(thr->racy_state[1]);
619ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
62039968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  if (IsFiredSuppression(ctx, rep, traces[1]))
62139968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    return;
6227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (HandleRacyStacks(thr, traces, addr_min, addr_max))
6247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
6257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
626069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  for (uptr i = 0; i < kMop; i++) {
6277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Shadow s(thr->racy_state[i]);
6286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    rep.AddMemoryAccess(addr, s, traces[i],
629ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov                        i == 0 ? &thr->mset : mset2.data());
6307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
6317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
632069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  for (uptr i = 0; i < kMop; i++) {
6337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    FastState s(thr->racy_state[i]);
6342bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    ThreadContext *tctx = static_cast<ThreadContext*>(
6352bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov        ctx->thread_registry->GetThreadLocked(s.tid()));
6367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1)
6377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      continue;
6387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    rep.AddThread(tctx);
6397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
6407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
641ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  rep.AddLocation(addr_min, addr_max - addr_min);
642ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov
64386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
644848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  {  // NOLINT
645848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    Shadow s(thr->racy_state[1]);
646848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    if (s.epoch() <= thr->last_sleep_clock.get(s.tid()))
647848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov      rep.AddSleep(thr->last_sleep_stack_id);
648848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  }
649848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov#endif
650848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
6516a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (!OutputReport(thr, rep))
6527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
6537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  AddRacyStacks(thr, traces, addr_min, addr_max);
6557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
6567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6571da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintCurrentStack(ThreadState *thr, uptr pc) {
6586d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  VarSizeStackTrace trace;
6596d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  ObtainCurrentStack(thr, pc, &trace);
6601da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  PrintStack(SymbolizeStack(trace));
6611da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov}
6621da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov
6636d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid PrintCurrentStackSlow(uptr pc) {
66486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
6656d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  BufferedStackTrace *ptrace =
6666d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
6676d1862363c88c183b0ed7740fca876342cf0474bStephen Hines          BufferedStackTrace();
6686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false);
669924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov  for (uptr i = 0; i < ptrace->size / 2; i++) {
6706d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    uptr tmp = ptrace->trace_buffer[i];
6716d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
6726d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
673924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov  }
6746d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  PrintStack(SymbolizeStack(*ptrace));
675793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov#endif
676793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov}
677793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov
6787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
6796d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
6806d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesusing namespace __tsan;
6816d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
6826d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesextern "C" {
6836d1862363c88c183b0ed7740fca876342cf0474bStephen HinesSANITIZER_INTERFACE_ATTRIBUTE
6846d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid __sanitizer_print_stack_trace() {
6856d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
6866d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
6876d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}  // extern "C"
688