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
33793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukovstatic ReportStack *SymbolizeStack(const 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);
44793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  PrintCurrentStackSlow();
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
597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void StackStripMain(ReportStack *stack) {
607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack *last_frame = 0;
617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack *last_frame2 = 0;
62f54c0e3321e2381fca3f02faefaaa6639d59c7cfDmitry Vyukov  const char *prefix = "__interceptor_";
637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr prefix_len = internal_strlen(prefix);
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *path_prefix = flags()->strip_path_prefix;
657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr path_prefix_len = internal_strlen(path_prefix);
6687dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov  char *pos;
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (ReportStack *ent = stack; ent; ent = ent->next) {
68d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov    if (ent->func && 0 == internal_strncmp(ent->func, prefix, prefix_len))
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ent->func += prefix_len;
7087dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov    if (ent->file && (pos = internal_strstr(ent->file, path_prefix)))
7187dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov      ent->file = pos + path_prefix_len;
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->file && ent->file[0] == '.' && ent->file[1] == '/')
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ent->file += 2;
747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2 = last_frame;
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame = ent;
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (last_frame2 == 0)
797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *last = last_frame->func;
81cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#ifndef TSAN_GO
827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *last2 = last_frame2->func;
837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip frame above 'main'
847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (last2 && 0 == internal_strcmp(last2, "main")) {
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2->next = 0;
867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip our internal thread start routine.
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) {
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2->next = 0;
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip global ctors init.
907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) {
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2->next = 0;
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // If both are 0, then we probably just failed to symbolize.
937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last || last2) {
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // Ensure that we recovered stack completely. Trimmed stack
957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // can actually happen if we do not instrument some code,
960ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    // so it's only a debug print. However we must try hard to not miss it
977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // due to our fault.
980ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
100cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#else
1011dc5f39fbcb09734809b73eb16dd64b50d647038Dmitry Vyukov  // The last frame always point into runtime (gosched0, goexit0, runtime.main).
1021dc5f39fbcb09734809b73eb16dd64b50d647038Dmitry Vyukov  last_frame2->next = 0;
1031dc5f39fbcb09734809b73eb16dd64b50d647038Dmitry Vyukov  (void)last;
104c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesReportStack *SymbolizeStackId(u32 stack_id) {
1082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (stack_id == 0)
1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr ssz = 0;
1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  const uptr *stack = StackDepotGet(stack_id, &ssz);
1122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (stack == 0)
1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
1142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  StackTrace trace;
1152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  trace.Init(stack, ssz);
1162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return SymbolizeStack(trace);
1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic ReportStack *SymbolizeStack(const StackTrace& trace) {
1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (trace.IsEmpty())
1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return 0;
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack *stack = 0;
1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr si = 0; si < trace.Size(); si++) {
124e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    const uptr pc = trace.Get(si);
125e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov#ifndef TSAN_GO
1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // We obtain the return address, that is, address of the next instruction,
1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // so offset it by 1 byte.
128e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
129e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov#else
130e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    // FIXME(dvyukov): Go sometimes uses address of a function as top pc.
131e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    uptr pc1 = pc;
132e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    if (si != trace.Size() - 1)
133e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov      pc1 -= 1;
134e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov#endif
135e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    ReportStack *ent = SymbolizeCode(pc1);
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK_NE(ent, 0);
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ReportStack *last = ent;
1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (last->next) {
139e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov      last->pc = pc;  // restore original pc for report
1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      last = last->next;
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
142e7718bcc1372d25fc21100e403cf41b166d42f9bDmitry Vyukov    last->pc = pc;  // restore original pc for report
1437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last->next = stack;
1447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stack = ent;
1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StackStripMain(stack);
1477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return stack;
1487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1507ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::ScopedReport(ReportType typ) {
1512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->thread_registry->CheckLocked();
1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
1537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_ = new(mem) ReportDesc;
1547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->typ = typ;
1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->report_mtx.Lock();
1567ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov  CommonSanitizerReportMutex.Lock();
1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1597ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::~ScopedReport() {
1607ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov  CommonSanitizerReportMutex.Unlock();
1612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->report_mtx.Unlock();
162aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  DestroyAndFree(rep_);
1637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1655d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesvoid ScopedReport::AddStack(const StackTrace *stack, bool suppressable) {
1667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack **rs = rep_->stacks.PushBack();
1677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  *rs = SymbolizeStack(*stack);
1685d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  (*rs)->suppressable = suppressable;
1697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
172ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    const StackTrace *stack, const MutexSet *mset) {
1737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
1747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportMop *mop = new(mem) ReportMop;
1757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->mops.PushBack(mop);
1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->tid = s.tid();
1777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->addr = addr + s.addr0();
1787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->size = s.size();
179334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov  mop->write = s.IsWrite();
1800a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  mop->atomic = s.IsAtomic();
1817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->stack = SymbolizeStack(*stack);
1825d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  if (mop->stack)
1835d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    mop->stack->suppressable = true;
184ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset->Size(); i++) {
185ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    MutexSet::Desc d = mset->Get(i);
1862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    u64 mid = this->AddMutex(d.id);
1872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ReportMopMutex mtx = {mid, d.write};
1882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    mop->mset.PushBack(mtx);
189ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ScopedReport::AddUniqueTid(int unique_tid) {
1932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rep_->unique_tids.PushBack(unique_tid);
1942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1965d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesvoid ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
197ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  for (uptr i = 0; i < rep_->threads.Size(); i++) {
1982bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    if ((u32)rep_->threads[i]->id == tctx->tid)
199ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      return;
200ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
2027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportThread *rt = new(mem) ReportThread();
2037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->threads.PushBack(rt);
2047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->id = tctx->tid;
2057dccf3f92a867f917ad19f9a6b37bcf93e64b35bDmitry Vyukov  rt->pid = tctx->os_id;
2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->running = (tctx->status == ThreadStatusRunning);
2072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rt->name = internal_strdup(tctx->name);
2082bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  rt->parent_tid = tctx->parent_tid;
2092c5284e0f87e101e177a151fae5f557bcf6f664cDmitry Vyukov  rt->stack = 0;
2102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rt->stack = SymbolizeStackId(tctx->creation_stack_id);
2115d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  if (rt->stack)
2125d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    rt->stack->suppressable = suppressable;
2137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2150ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#ifndef TSAN_GO
216df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonovstatic ThreadContext *FindThreadByUidLocked(int unique_id) {
2172bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ctx->thread_registry->CheckLocked();
218ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  for (unsigned i = 0; i < kMaxTid; i++) {
2192bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    ThreadContext *tctx = static_cast<ThreadContext*>(
2202bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov        ctx->thread_registry->GetThreadLocked(i));
2212bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    if (tctx && tctx->unique_id == (u32)unique_id) {
222ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      return tctx;
223ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    }
224ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
225ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  return 0;
226ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov}
227fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov
228f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukovstatic ThreadContext *FindThreadByTidLocked(int tid) {
229f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov  ctx->thread_registry->CheckLocked();
230f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov  return static_cast<ThreadContext*>(
231f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov      ctx->thread_registry->GetThreadLocked(tid));
232f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov}
233f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov
234df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonovstatic bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) {
235df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  uptr addr = (uptr)arg;
236df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
237df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  if (tctx->status != ThreadStatusRunning)
238df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov    return false;
239df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadState *thr = tctx->thr;
240df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  CHECK(thr);
241df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  return ((addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) ||
242df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov          (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size));
243df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov}
244df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov
245fb917e9069ea44f7103f50c658be84a8f66de56cDmitry VyukovThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
2462bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ctx->thread_registry->CheckLocked();
247df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadContext *tctx = static_cast<ThreadContext*>(
248df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov      ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls,
249df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov                                                    (void*)addr));
250df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  if (!tctx)
251df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov    return 0;
252df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  ThreadState *thr = tctx->thr;
253df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  CHECK(thr);
254df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  *is_stack = (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size);
255df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov  return tctx;
256fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov}
2570ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
258ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov
2595d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesvoid ScopedReport::AddThread(int unique_tid, bool suppressable) {
2602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#ifndef TSAN_GO
2615d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  AddThread(FindThreadByUidLocked(unique_tid), suppressable);
2622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif
2632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
2642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
2657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMutex(const SyncVar *s) {
266ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
267ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (rep_->mutexes[i]->id == s->uid)
268ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      return;
269ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
2707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
2717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportMutex *rm = new(mem) ReportMutex();
2727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->mutexes.PushBack(rm);
273ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->id = s->uid;
2742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rm->addr = s->addr;
275ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->destroyed = false;
2762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rm->stack = SymbolizeStackId(s->creation_stack_id);
2772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
2782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
2792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesu64 ScopedReport::AddMutex(u64 id) {
2802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  u64 uid = 0;
2812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  u64 mid = id;
2822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr addr = SyncVar::SplitId(id, &uid);
2835d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
2842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Check that the mutex is still alive.
2852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Another mutex can be created at the same address,
2862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // so check uid as well.
2872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (s && s->CheckId(uid)) {
2882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    mid = s->uid;
2892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    AddMutex(s);
2902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  } else {
2912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    AddDeadMutex(id);
2922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
2932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (s)
2945d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    s->mtx.Unlock();
2952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return mid;
2967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ScopedReport::AddDeadMutex(u64 id) {
299ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
300ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (rep_->mutexes[i]->id == id)
301ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      return;
302ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
303ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
304ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  ReportMutex *rm = new(mem) ReportMutex();
305ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rep_->mutexes.PushBack(rm);
306ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->id = id;
3072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rm->addr = 0;
308ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->destroyed = true;
309ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->stack = 0;
310ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
311ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
3127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddLocation(uptr addr, uptr size) {
313ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  if (addr == 0)
314ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
315ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov#ifndef TSAN_GO
316c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  int fd = -1;
317c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  int creat_tid = -1;
318c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  u32 creat_stack = 0;
319c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  if (FdLocation(addr, &fd, &creat_tid, &creat_stack)
320c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      || FdLocation(AlternativeAddress(addr), &fd, &creat_tid, &creat_stack)) {
321c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
322c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    ReportLocation *loc = new(mem) ReportLocation();
323c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    rep_->locs.PushBack(loc);
324c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->type = ReportLocationFD;
325c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->fd = fd;
326c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->tid = creat_tid;
3272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    loc->stack = SymbolizeStackId(creat_stack);
328df2ca17ae60fc2116a32fc201deb704e1c8b2114Alexey Samsonov    ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
329c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    if (tctx)
330c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      AddThread(tctx);
331c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    return;
332c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  }
33303049413f8978c202a254eb0acfa2f10b9bbe34aDmitry Vyukov  MBlock *b = 0;
3345d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  Allocator *a = allocator();
3355d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  if (a->PointerIsMine((void*)addr)) {
3365d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    void *block_begin = a->GetBlockBegin((void*)addr);
3375d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    if (block_begin)
3385d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines      b = ctx->metamap.GetBlock((uptr)block_begin);
3395d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  }
3405d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  if (b != 0) {
3415d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    ThreadContext *tctx = FindThreadByTidLocked(b->tid);
342ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
343ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    ReportLocation *loc = new(mem) ReportLocation();
344ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    rep_->locs.PushBack(loc);
345ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->type = ReportLocationHeap;
346ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->addr = (uptr)allocator()->GetBlockBegin((void*)addr);
3475d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    loc->size = b->siz;
3485d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    loc->tid = tctx ? tctx->tid : b->tid;
349ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->name = 0;
350ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->file = 0;
351ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->line = 0;
352ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->stack = 0;
3535d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    loc->stack = SymbolizeStackId(b->stk);
354ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (tctx)
355ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      AddThread(tctx);
356ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
357ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
358fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  bool is_stack = false;
359fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
360fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
361fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    ReportLocation *loc = new(mem) ReportLocation();
362fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    rep_->locs.PushBack(loc);
363fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
364fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    loc->tid = tctx->tid;
365fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    AddThread(tctx);
366fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  }
3675a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov  ReportLocation *loc = SymbolizeData(addr);
3685a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov  if (loc) {
3695d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    loc->suppressable = true;
3707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    rep_->locs.PushBack(loc);
371ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
3727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
373fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov#endif
3747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3760ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#ifndef TSAN_GO
377848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovvoid ScopedReport::AddSleep(u32 stack_id) {
3782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  rep_->sleep = SymbolizeStackId(stack_id);
379848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
3800ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
381848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
3824536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukovvoid ScopedReport::SetCount(int count) {
3834536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov  rep_->count = count;
3844536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov}
3854536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov
3867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst ReportDesc *ScopedReport::GetReport() const {
3877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return rep_;
3887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
390ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovvoid RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
391ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // This function restores stack trace and mutex set for the thread/epoch.
392ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // It does so by getting stack trace and mutex set at the beginning of
393ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // trace part, and then replaying the trace till the given epoch.
3942bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ctx->thread_registry->CheckLocked();
3952bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ThreadContext *tctx = static_cast<ThreadContext*>(
3962bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov      ctx->thread_registry->GetThreadLocked(tid));
3977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (tctx == 0)
3987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
3999743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  if (tctx->status != ThreadStatusRunning
4009743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov      && tctx->status != ThreadStatusFinished
4019743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov      && tctx->status != ThreadStatusDead)
4027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
4039743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  Trace* trace = ThreadTrace(tctx->tid);
4047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Lock l(&trace->mtx);
4050415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  const int partidx = (epoch / kTracePartSize) % TraceParts();
4067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  TraceHeader* hdr = &trace->headers[partidx];
4077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (epoch < hdr->epoch0)
4087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
409ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  const u64 epoch0 = RoundDown(epoch, TraceSize());
410d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov  const u64 eend = epoch % TraceSize();
4110415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  const u64 ebegin = RoundDown(eend, kTracePartSize);
412e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov  DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
413e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov          tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
41401a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov  InternalScopedBuffer<uptr> stack(kShadowStackSize);
4157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < hdr->stack0.Size(); i++) {
4167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stack[i] = hdr->stack0.Get(i);
417e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    DPrintf2("  #%02lu: pc=%zx\n", i, stack[i]);
4187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
419ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (mset)
420ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    *mset = hdr->mset0;
4217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr pos = hdr->stack0.Size();
422385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  Event *events = (Event*)GetThreadTrace(tid);
4237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = ebegin; i <= eend; i++) {
424385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov    Event ev = events[i];
4257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    EventType typ = (EventType)(ev >> 61);
426ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    uptr pc = (uptr)(ev & ((1ull << 61) - 1));
427e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    DPrintf2("  %zu typ=%d pc=%zx\n", i, typ, pc);
4287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (typ == EventTypeMop) {
4297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      stack[pos] = pc;
4307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    } else if (typ == EventTypeFuncEnter) {
4317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      stack[pos++] = pc;
4327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    } else if (typ == EventTypeFuncExit) {
4337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (pos > 0)
4347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        pos--;
4357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
436ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (mset) {
437ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      if (typ == EventTypeLock) {
438ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Add(pc, true, epoch0 + i);
439ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeUnlock) {
440ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Del(pc, true);
441ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeRLock) {
442ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Add(pc, false, epoch0 + i);
443ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeRUnlock) {
444ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Del(pc, false);
445ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      }
446ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    }
4477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr j = 0; j <= pos; j++)
448e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov      DPrintf2("      #%zu: %zx\n", j, stack[j]);
4497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (pos == 0 && stack[0] == 0)
4517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
4527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  pos++;
4531dc4cf7e253aefa3ce3bd4a1d349a13647e8b2eaAlexey Samsonov  stk->Init(stack.data(), pos);
4547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
4577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr addr_min, uptr addr_max) {
4587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool equal_stack = false;
459e0c45610e138c9e0b518189b7fa286f4b7ee6474Dmitry Vyukov  RacyStacks hash;
4607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_stacks) {
4617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
4627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
4637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
4647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (hash == ctx->racy_stacks[i]) {
4657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
4667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        equal_stack = true;
4677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
4687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
4697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
4707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool equal_address = false;
4727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  RacyAddress ra0 = {addr_min, addr_max};
4737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_addresses) {
4747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
4757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      RacyAddress ra2 = ctx->racy_addresses[i];
4767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
4777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      uptr minend = min(ra0.addr_max, ra2.addr_max);
4787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (maxbeg < minend) {
4797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n");
4807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        equal_address = true;
4817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
4827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
4837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
4847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (equal_stack || equal_address) {
4867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (!equal_stack)
4877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ctx->racy_stacks.PushBack(hash);
4887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (!equal_address)
4897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ctx->racy_addresses.PushBack(ra0);
4907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return true;
4917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return false;
4937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
4967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr addr_min, uptr addr_max) {
4977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_stacks) {
498e0c45610e138c9e0b518189b7fa286f4b7ee6474Dmitry Vyukov    RacyStacks hash;
4997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
5007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
5017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ctx->racy_stacks.PushBack(hash);
5027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
5037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_addresses) {
5047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    RacyAddress ra0 = {addr_min, addr_max};
5057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ctx->racy_addresses.PushBack(ra0);
5067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
5077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5095d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesbool OutputReport(ThreadState *thr, const ScopedReport &srep) {
510a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov  atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
5117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const ReportDesc *rep = srep.GetReport();
512f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov  Suppression *supp = 0;
5135d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  uptr suppress_pc = 0;
5145d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++)
5155d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp);
5165d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++)
5175d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp);
5185d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++)
5195d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp);
5205d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++)
5215d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp);
522158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (suppress_pc != 0) {
523f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov    FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
5240a05e5fa28a7424f8146549057c53b4590f3a251Alexey Samsonov    ctx->fired_suppressions.push_back(s);
525158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  }
5265d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  {
5275d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    bool old_is_freeing = thr->is_freeing;
5285d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    thr->is_freeing = false;
5295d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    bool suppressed = OnReport(rep, suppress_pc != 0);
5305d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    thr->is_freeing = old_is_freeing;
5315d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines    if (suppressed)
5325d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines      return false;
5335d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  }
5347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintReport(rep);
535dbac0a4a41f405d10e3dcad3597fe08986605289Dmitry Vyukov  ctx->nreported++;
536dbac0a4a41f405d10e3dcad3597fe08986605289Dmitry Vyukov  if (flags()->halt_on_error)
537dbac0a4a41f405d10e3dcad3597fe08986605289Dmitry Vyukov    internal__exit(flags()->exitcode);
5387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return true;
5397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
541158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukovbool IsFiredSuppression(Context *ctx,
542158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov                        const ScopedReport &srep,
543158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov                        const StackTrace &trace) {
5440a05e5fa28a7424f8146549057c53b4590f3a251Alexey Samsonov  for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
545158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
546158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov      continue;
547158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    for (uptr j = 0; j < trace.Size(); j++) {
548f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov      FiredSuppression *s = &ctx->fired_suppressions[k];
549f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov      if (trace.Get(j) == s->pc) {
550f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov        if (s->supp)
551f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov          s->supp->hit_count++;
552158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov        return true;
553f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov      }
554158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    }
555158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  }
556158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  return false;
557158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov}
558158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov
55939968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukovstatic bool IsFiredSuppression(Context *ctx,
56039968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov                               const ScopedReport &srep,
56139968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov                               uptr addr) {
5620a05e5fa28a7424f8146549057c53b4590f3a251Alexey Samsonov  for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
56339968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
56439968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov      continue;
56539968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    FiredSuppression *s = &ctx->fired_suppressions[k];
56639968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    if (addr == s->pc) {
56739968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov      if (s->supp)
56839968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov        s->supp->hit_count++;
56939968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov      return true;
57039968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    }
57139968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  }
57239968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  return false;
57339968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov}
57439968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov
5752f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanybool FrameIsInternal(const ReportStack *frame) {
5762f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return frame != 0 && frame->file != 0
5772f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany      && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
5789dbba15ba91b55f87a25feb284e43ab7a9be31b3Kostya Serebryany          internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
5799dbba15ba91b55f87a25feb284e43ab7a9be31b3Kostya Serebryany          internal_strstr(frame->file, "tsan_interface_"));
5802f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
5812f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
582543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov// On programs that use Java we see weird reports like:
583543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov// WARNING: ThreadSanitizer: data race (pid=22512)
584543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//   Read of size 8 at 0x7d2b00084318 by thread 100:
585543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #0 memcpy tsan_interceptors.cc:406 (foo+0x00000d8dfae3)
586543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #1 <null> <null>:0 (0x7f7ad9b40193)
587543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//   Previous write of size 8 at 0x7d2b00084318 by thread 105:
588543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
589543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #1 <null> <null>:0 (0x7f7ad9b42707)
590543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukovstatic bool IsJavaNonsense(const ReportDesc *rep) {
5916cf1e6d92200f61bf275ca433c88c60c934e3086Dmitry Vyukov#ifndef TSAN_GO
592543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  for (uptr i = 0; i < rep->mops.Size(); i++) {
593543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    ReportMop *mop = rep->mops[i];
594543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    ReportStack *frame = mop->stack;
595e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov    if (frame == 0
596e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov        || (frame->func == 0 && frame->file == 0 && frame->line == 0
597e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov          && frame->module == 0)) {
598e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov      return true;
599e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov    }
600e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov    if (FrameIsInternal(frame)) {
601e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov      frame = frame->next;
602e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov      if (frame == 0
603e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov          || (frame->func == 0 && frame->file == 0 && frame->line == 0
6045ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov          && frame->module == 0)) {
605e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov        if (frame) {
606f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov          FiredSuppression supp = {rep->typ, frame->pc, 0};
6072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          ctx->fired_suppressions.push_back(supp);
608e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov        }
609e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov        return true;
610e47115fa033f3e3bd906dabe8beebc2e29e722d0Dmitry Vyukov      }
611543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    }
612543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  }
6136cf1e6d92200f61bf275ca433c88c60c934e3086Dmitry Vyukov#endif
614543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  return false;
615543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov}
616543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov
6173285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukovstatic bool RaceBetweenAtomicAndFree(ThreadState *thr) {
6183285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  Shadow s0(thr->racy_state[0]);
6193285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  Shadow s1(thr->racy_state[1]);
6203285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
6213285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (!s0.IsAtomic() && !s1.IsAtomic())
6223285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
6233285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (s0.IsAtomic() && s1.IsFreed())
6243285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
6253285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (s1.IsAtomic() && thr->is_freeing)
6263285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
6273285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  return false;
6283285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov}
6293285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov
6307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ReportRace(ThreadState *thr) {
6315d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  CheckNoLocks(thr);
6325d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines
6332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Symbolizer makes lots of intercepted calls. If we try to process them,
6342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // at best it will cause deadlocks on internal mutexes.
6352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ScopedIgnoreInterceptors ignore;
6362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
6378a326776e41dc68c810ba3719a24328de517d8f9Dmitry Vyukov  if (!flags()->report_bugs)
6388a326776e41dc68c810ba3719a24328de517d8f9Dmitry Vyukov    return;
6393285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
6403285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return;
6413285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov
642069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  bool freed = false;
643069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  {
644069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    Shadow s(thr->racy_state[1]);
645069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    freed = s.GetFreedAndReset();
646069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    thr->racy_state[1] = s.raw();
647069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  }
648069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov
6497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr);
6507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr_min = 0;
6517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr_max = 0;
6527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
6537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr a0 = addr + Shadow(thr->racy_state[0]).addr0();
6547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr a1 = addr + Shadow(thr->racy_state[1]).addr0();
6557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr e0 = a0 + Shadow(thr->racy_state[0]).size();
6567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr e1 = a1 + Shadow(thr->racy_state[1]).size();
6577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr_min = min(a0, a1);
6587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr_max = max(e0, e1);
6597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (IsExpectedReport(addr_min, addr_max - addr_min))
6607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      return;
6617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
6627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6632bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  ThreadRegistryLock l0(ctx->thread_registry);
6647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6650dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  ReportType typ = ReportTypeRace;
6660dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  if (thr->is_vptr_access)
6670dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    typ = ReportTypeVptrRace;
6680dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  else if (freed)
6690dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    typ = ReportTypeUseAfterFree;
6700dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  ScopedReport rep(typ);
67139968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  if (IsFiredSuppression(ctx, rep, addr))
67239968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    return;
673069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  const uptr kMop = 2;
674069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  StackTrace traces[kMop];
675385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  const uptr toppc = TraceTopPC(thr);
676158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  traces[0].ObtainCurrent(thr, toppc);
677158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (IsFiredSuppression(ctx, rep, traces[0]))
678158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    return;
679ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  InternalScopedBuffer<MutexSet> mset2(1);
680ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  new(mset2.data()) MutexSet();
681158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  Shadow s2(thr->racy_state[1]);
682ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
68339968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov  if (IsFiredSuppression(ctx, rep, traces[1]))
68439968339a07d790aadcf27534f92a0de8c0c90fbDmitry Vyukov    return;
6857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (HandleRacyStacks(thr, traces, addr_min, addr_max))
6877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
6887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
689069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  for (uptr i = 0; i < kMop; i++) {
6907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Shadow s(thr->racy_state[i]);
691ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    rep.AddMemoryAccess(addr, s, &traces[i],
692ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov                        i == 0 ? &thr->mset : mset2.data());
6937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
6947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
695543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  if (flags()->suppress_java && IsJavaNonsense(rep.GetReport()))
696543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    return;
697543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov
698069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  for (uptr i = 0; i < kMop; i++) {
6997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    FastState s(thr->racy_state[i]);
7002bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov    ThreadContext *tctx = static_cast<ThreadContext*>(
7012bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov        ctx->thread_registry->GetThreadLocked(s.tid()));
7027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1)
7037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      continue;
7047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    rep.AddThread(tctx);
7057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
7067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
707ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  rep.AddLocation(addr_min, addr_max - addr_min);
708ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov
709848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov#ifndef TSAN_GO
710848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  {  // NOLINT
711848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    Shadow s(thr->racy_state[1]);
712848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    if (s.epoch() <= thr->last_sleep_clock.get(s.tid()))
713848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov      rep.AddSleep(thr->last_sleep_stack_id);
714848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  }
715848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov#endif
716848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
7175d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines  if (!OutputReport(thr, rep))
7187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
7197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
7207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  AddRacyStacks(thr, traces, addr_min, addr_max);
7217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
7227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
7231da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintCurrentStack(ThreadState *thr, uptr pc) {
7241da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  StackTrace trace;
7251da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  trace.ObtainCurrent(thr, pc);
7261da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  PrintStack(SymbolizeStack(trace));
7271da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov}
7281da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov
729793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukovvoid PrintCurrentStackSlow() {
730793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov#ifndef TSAN_GO
731793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
732793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov      sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
7332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(), 0, 0,
7342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                 0, 0, false);
735924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov  for (uptr i = 0; i < ptrace->size / 2; i++) {
736924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov    uptr tmp = ptrace->trace[i];
737924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov    ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
738924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov    ptrace->trace[ptrace->size - i - 1] = tmp;
739924047f32220f8da9c308acddbc0a41b952e7a0dDmitry Vyukov  }
740793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  StackTrace trace;
741793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  trace.Init(ptrace->trace, ptrace->size);
742793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  PrintStack(SymbolizeStack(trace));
743793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov#endif
744793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov}
745793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov
7467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
747