tsan_rtl_report.cc revision 2f588f9d3417aa107ebbbd8830f97501023d3f40
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) {
3715a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  ScopedInRtl in_rtl;
38b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("FATAL: ThreadSanitizer CHECK failed: "
39b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov         "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
40b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov         file, line, cond, (uptr)v1, (uptr)v2);
41793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  PrintCurrentStackSlow();
4215a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  Die();
4315a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov}
4415a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// Can be overriden by an application/test to intercept reports.
4687dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov#ifdef TSAN_EXTERNAL_HOOKS
4787dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukovbool OnReport(const ReportDesc *rep, bool suppressed);
4887dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov#else
499a46c3b7aeb3a800702b48dd5f8017b0ae7387c7Alexey SamsonovSANITIZER_INTERFACE_ATTRIBUTE
507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanybool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  (void)rep;
527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return suppressed;
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5487dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov#endif
557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void StackStripMain(ReportStack *stack) {
577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack *last_frame = 0;
587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack *last_frame2 = 0;
59f54c0e3321e2381fca3f02faefaaa6639d59c7cfDmitry Vyukov  const char *prefix = "__interceptor_";
607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr prefix_len = internal_strlen(prefix);
617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *path_prefix = flags()->strip_path_prefix;
627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr path_prefix_len = internal_strlen(path_prefix);
6387dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov  char *pos;
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (ReportStack *ent = stack; ent; ent = ent->next) {
65d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov    if (ent->func && 0 == internal_strncmp(ent->func, prefix, prefix_len))
667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ent->func += prefix_len;
6787dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov    if (ent->file && (pos = internal_strstr(ent->file, path_prefix)))
6887dbdf5fd6cb9f1b90a0a97b7675bd8cad8a0264Dmitry Vyukov      ent->file = pos + path_prefix_len;
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->file && ent->file[0] == '.' && ent->file[1] == '/')
707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ent->file += 2;
717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2 = last_frame;
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame = ent;
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (last_frame2 == 0)
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *last = last_frame->func;
78cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#ifndef TSAN_GO
797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *last2 = last_frame2->func;
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip frame above 'main'
817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (last2 && 0 == internal_strcmp(last2, "main")) {
827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2->next = 0;
837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip our internal thread start routine.
847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) {
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2->next = 0;
867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Strip global ctors init.
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) {
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last_frame2->next = 0;
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // If both are 0, then we probably just failed to symbolize.
907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (last || last2) {
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // Ensure that we recovered stack completely. Trimmed stack
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // can actually happen if we do not instrument some code,
930ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    // so it's only a debug print. However we must try hard to not miss it
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // due to our fault.
950ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
97cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#else
98cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov  if (last && 0 == internal_strcmp(last, "schedunlock"))
99cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov    last_frame2->next = 0;
100c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic ReportStack *SymbolizeStack(const StackTrace& trace) {
1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (trace.IsEmpty())
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return 0;
1067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack *stack = 0;
1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr si = 0; si < trace.Size(); si++) {
1087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // We obtain the return address, that is, address of the next instruction,
1097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    // so offset it by 1 byte.
1107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    bool is_last = (si == trace.Size() - 1);
1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ReportStack *ent = SymbolizeCode(trace.Get(si) - !is_last);
1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK_NE(ent, 0);
1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ReportStack *last = ent;
1147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (last->next) {
1157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      last->pc += !is_last;
1167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      last = last->next;
1177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last->pc += !is_last;
1197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    last->next = stack;
1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stack = ent;
1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StackStripMain(stack);
1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return stack;
1247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1267ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::ScopedReport(ReportType typ) {
1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ctx_ = CTX();
128fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  ctx_->thread_mtx.CheckLocked();
1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_ = new(mem) ReportDesc;
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->typ = typ;
1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ctx_->report_mtx.Lock();
1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1357ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::~ScopedReport() {
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ctx_->report_mtx.Unlock();
137aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  DestroyAndFree(rep_);
1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddStack(const StackTrace *stack) {
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportStack **rs = rep_->stacks.PushBack();
1427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  *rs = SymbolizeStack(*stack);
1437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
146ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    const StackTrace *stack, const MutexSet *mset) {
1477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
1487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportMop *mop = new(mem) ReportMop;
1497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->mops.PushBack(mop);
1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->tid = s.tid();
1517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->addr = addr + s.addr0();
1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->size = s.size();
153334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov  mop->write = s.IsWrite();
1540a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  mop->atomic = s.IsAtomic();
1557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  mop->stack = SymbolizeStack(*stack);
156ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset->Size(); i++) {
157ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    MutexSet::Desc d = mset->Get(i);
158ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    u64 uid = 0;
159ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    uptr addr = SyncVar::SplitId(d.id, &uid);
160ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    SyncVar *s = ctx_->synctab.GetIfExistsAndLock(addr, false);
161ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    // Check that the mutex is still alive.
162ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    // Another mutex can be created at the same address,
163ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    // so check uid as well.
164ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (s && s->CheckId(uid)) {
165ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      ReportMopMutex mtx = {s->uid, d.write};
166ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      mop->mset.PushBack(mtx);
167ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      AddMutex(s);
168ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    } else {
169ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      ReportMopMutex mtx = {d.id, d.write};
170ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      mop->mset.PushBack(mtx);
171ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      AddMutex(d.id);
172ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    }
173ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (s)
174ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      s->mtx.ReadUnlock();
175ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddThread(const ThreadContext *tctx) {
179ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  for (uptr i = 0; i < rep_->threads.Size(); i++) {
180ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (rep_->threads[i]->id == tctx->tid)
181ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      return;
182ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
1837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
1847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportThread *rt = new(mem) ReportThread();
1857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->threads.PushBack(rt);
1867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->id = tctx->tid;
1877dccf3f92a867f917ad19f9a6b37bcf93e64b35bDmitry Vyukov  rt->pid = tctx->os_id;
1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->running = (tctx->status == ThreadStatusRunning);
189aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  rt->name = tctx->name ? internal_strdup(tctx->name) : 0;
190da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  rt->parent_tid = tctx->creation_tid;
1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rt->stack = SymbolizeStack(tctx->creation_stack);
1927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1940ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#ifndef TSAN_GO
195ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukovstatic ThreadContext *FindThread(int unique_id) {
196fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  Context *ctx = CTX();
197fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  ctx->thread_mtx.CheckLocked();
198ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  for (unsigned i = 0; i < kMaxTid; i++) {
199fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    ThreadContext *tctx = ctx->threads[i];
200ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (tctx && tctx->unique_id == unique_id) {
201ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      return tctx;
202ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    }
203ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
204ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  return 0;
205ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov}
206fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov
207fb917e9069ea44f7103f50c658be84a8f66de56cDmitry VyukovThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
208fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  Context *ctx = CTX();
209fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  ctx->thread_mtx.CheckLocked();
210fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  for (unsigned i = 0; i < kMaxTid; i++) {
211fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    ThreadContext *tctx = ctx->threads[i];
212fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    if (tctx == 0 || tctx->status != ThreadStatusRunning)
213fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov      continue;
214fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    ThreadState *thr = tctx->thr;
215fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    CHECK(thr);
216fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    if (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) {
217fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov      *is_stack = true;
218fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov      return tctx;
219fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    }
220fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    if (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size) {
221fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov      *is_stack = false;
222fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov      return tctx;
223fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    }
224fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  }
225fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  return 0;
226fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov}
2270ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
228ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov
2297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMutex(const SyncVar *s) {
230ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
231ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (rep_->mutexes[i]->id == s->uid)
232ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      return;
233ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
2347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
2357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportMutex *rm = new(mem) ReportMutex();
2367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rep_->mutexes.PushBack(rm);
237ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->id = s->uid;
238ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->destroyed = false;
2397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  rm->stack = SymbolizeStack(s->creation_stack);
2407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
242ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovvoid ScopedReport::AddMutex(u64 id) {
243ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
244ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (rep_->mutexes[i]->id == id)
245ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      return;
246ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
247ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
248ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  ReportMutex *rm = new(mem) ReportMutex();
249ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rep_->mutexes.PushBack(rm);
250ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->id = id;
251ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->destroyed = true;
252ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  rm->stack = 0;
253ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
254ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
2557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddLocation(uptr addr, uptr size) {
256ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  if (addr == 0)
257ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
258ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov#ifndef TSAN_GO
259c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  int fd = -1;
260c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  int creat_tid = -1;
261c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  u32 creat_stack = 0;
262c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  if (FdLocation(addr, &fd, &creat_tid, &creat_stack)
263c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      || FdLocation(AlternativeAddress(addr), &fd, &creat_tid, &creat_stack)) {
264c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
265c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    ReportLocation *loc = new(mem) ReportLocation();
266c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    rep_->locs.PushBack(loc);
267c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->type = ReportLocationFD;
268c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->fd = fd;
269c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    loc->tid = creat_tid;
270c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    uptr ssz = 0;
271c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    const uptr *stack = StackDepotGet(creat_stack, &ssz);
272c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    if (stack) {
273c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      StackTrace trace;
274c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      trace.Init(stack, ssz);
275c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      loc->stack = SymbolizeStack(trace);
276c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    }
277c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    ThreadContext *tctx = FindThread(creat_tid);
278c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    if (tctx)
279c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov      AddThread(tctx);
280c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    return;
281c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  }
282ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  if (allocator()->PointerIsMine((void*)addr)) {
283ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    MBlock *b = user_mblock(0, (void*)addr);
284ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    ThreadContext *tctx = FindThread(b->alloc_tid);
285ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
286ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    ReportLocation *loc = new(mem) ReportLocation();
287ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    rep_->locs.PushBack(loc);
288ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->type = ReportLocationHeap;
289ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->addr = (uptr)allocator()->GetBlockBegin((void*)addr);
290ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->size = b->size;
291ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->tid = tctx ? tctx->tid : b->alloc_tid;
292ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->name = 0;
293ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->file = 0;
294ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->line = 0;
295ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    loc->stack = 0;
296ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    uptr ssz = 0;
297ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    const uptr *stack = StackDepotGet(b->alloc_stack_id, &ssz);
298ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (stack) {
299ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      StackTrace trace;
300ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      trace.Init(stack, ssz);
301ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      loc->stack = SymbolizeStack(trace);
302ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    }
303ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    if (tctx)
304ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov      AddThread(tctx);
305ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
306ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  }
307fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  bool is_stack = false;
308fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
309fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
310fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    ReportLocation *loc = new(mem) ReportLocation();
311fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    rep_->locs.PushBack(loc);
312fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
313fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    loc->tid = tctx->tid;
314fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    AddThread(tctx);
315fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  }
3165a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov  ReportLocation *loc = SymbolizeData(addr);
3175a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov  if (loc) {
3187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    rep_->locs.PushBack(loc);
319ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov    return;
3207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
321fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov#endif
3227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3240ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#ifndef TSAN_GO
325848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovvoid ScopedReport::AddSleep(u32 stack_id) {
326848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  uptr ssz = 0;
327848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  const uptr *stack = StackDepotGet(stack_id, &ssz);
328848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (stack) {
329848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    StackTrace trace;
330848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    trace.Init(stack, ssz);
331848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    rep_->sleep = SymbolizeStack(trace);
332848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  }
333848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
3340ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
335848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
3367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst ReportDesc *ScopedReport::GetReport() const {
3377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return rep_;
3387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
340ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovvoid RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
341ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // This function restores stack trace and mutex set for the thread/epoch.
342ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // It does so by getting stack trace and mutex set at the beginning of
343ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  // trace part, and then replaying the trace till the given epoch.
3447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ThreadContext *tctx = CTX()->threads[tid];
3457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (tctx == 0)
3467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
3477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Trace* trace = 0;
3487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (tctx->status == ThreadStatusRunning) {
3497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK(tctx->thr);
3507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    trace = &tctx->thr->trace;
3517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (tctx->status == ThreadStatusFinished
3527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      || tctx->status == ThreadStatusDead) {
3539d2ffc2ee08216f8fad9b1bd267d1f112e0d2f01Dmitry Vyukov    if (tctx->dead_info == 0)
3549d2ffc2ee08216f8fad9b1bd267d1f112e0d2f01Dmitry Vyukov      return;
3559d2ffc2ee08216f8fad9b1bd267d1f112e0d2f01Dmitry Vyukov    trace = &tctx->dead_info->trace;
3567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else {
3577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
3587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
3597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Lock l(&trace->mtx);
3600415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  const int partidx = (epoch / kTracePartSize) % TraceParts();
3617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  TraceHeader* hdr = &trace->headers[partidx];
3627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (epoch < hdr->epoch0)
3637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
364ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  const u64 epoch0 = RoundDown(epoch, TraceSize());
365d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov  const u64 eend = epoch % TraceSize();
3660415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  const u64 ebegin = RoundDown(eend, kTracePartSize);
367e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov  DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
368e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov          tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
36914c8bd7250742749e44e306c02a56cf47ad1db82Alexey Samsonov  InternalScopedBuffer<uptr> stack(1024);  // FIXME: de-hardcode 1024
3707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < hdr->stack0.Size(); i++) {
3717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    stack[i] = hdr->stack0.Get(i);
372e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    DPrintf2("  #%02lu: pc=%zx\n", i, stack[i]);
3737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
374ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (mset)
375ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    *mset = hdr->mset0;
3767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr pos = hdr->stack0.Size();
377385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  Event *events = (Event*)GetThreadTrace(tid);
3787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = ebegin; i <= eend; i++) {
379385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov    Event ev = events[i];
3807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    EventType typ = (EventType)(ev >> 61);
381ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    uptr pc = (uptr)(ev & ((1ull << 61) - 1));
382e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov    DPrintf2("  %zu typ=%d pc=%zx\n", i, typ, pc);
3837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (typ == EventTypeMop) {
3847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      stack[pos] = pc;
3857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    } else if (typ == EventTypeFuncEnter) {
3867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      stack[pos++] = pc;
3877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    } else if (typ == EventTypeFuncExit) {
3887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (pos > 0)
3897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        pos--;
3907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
391ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (mset) {
392ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      if (typ == EventTypeLock) {
393ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Add(pc, true, epoch0 + i);
394ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeUnlock) {
395ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Del(pc, true);
396ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeRLock) {
397ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Add(pc, false, epoch0 + i);
398ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      } else if (typ == EventTypeRUnlock) {
399ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        mset->Del(pc, false);
400ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      }
401ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    }
4027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr j = 0; j <= pos; j++)
403e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov      DPrintf2("      #%zu: %zx\n", j, stack[j]);
4047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (pos == 0 && stack[0] == 0)
4067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
4077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  pos++;
4081dc4cf7e253aefa3ce3bd4a1d349a13647e8b2eaAlexey Samsonov  stk->Init(stack.data(), pos);
4097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
4127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr addr_min, uptr addr_max) {
4137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Context *ctx = CTX();
4147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool equal_stack = false;
415175e6407c9d5f8bd0f36abd9c020e3888134ebd3Dmitry Vyukov  RacyStacks hash;
4167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_stacks) {
4177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
4187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
4197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
4207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (hash == ctx->racy_stacks[i]) {
4217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
4227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        equal_stack = true;
4237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
4247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
4257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
4267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool equal_address = false;
4287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  RacyAddress ra0 = {addr_min, addr_max};
4297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_addresses) {
4307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
4317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      RacyAddress ra2 = ctx->racy_addresses[i];
4327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
4337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      uptr minend = min(ra0.addr_max, ra2.addr_max);
4347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (maxbeg < minend) {
4357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n");
4367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        equal_address = true;
4377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
4387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
4397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
4407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (equal_stack || equal_address) {
4427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (!equal_stack)
4437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ctx->racy_stacks.PushBack(hash);
4447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (!equal_address)
4457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      ctx->racy_addresses.PushBack(ra0);
4467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return true;
4477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return false;
4497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
4527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr addr_min, uptr addr_max) {
4537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Context *ctx = CTX();
4547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_stacks) {
4557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    RacyStacks hash;
4567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
4577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
4587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ctx->racy_stacks.PushBack(hash);
4597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (flags()->suppress_equal_addresses) {
4617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    RacyAddress ra0 = {addr_min, addr_max};
4627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ctx->racy_addresses.PushBack(ra0);
4637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
466158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukovbool OutputReport(Context *ctx,
467158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov                  const ScopedReport &srep,
468e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov                  const ReportStack *suppress_stack1,
469e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov                  const ReportStack *suppress_stack2) {
4707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const ReportDesc *rep = srep.GetReport();
471e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
472e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov  if (suppress_pc == 0)
473e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov    suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
474158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (suppress_pc != 0) {
475158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
476158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    ctx->fired_suppressions.PushBack(supp);
477158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  }
478158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (OnReport(rep, suppress_pc != 0))
4797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return false;
4807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintReport(rep);
4817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  CTX()->nreported++;
4827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return true;
4837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
485158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukovbool IsFiredSuppression(Context *ctx,
486158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov                        const ScopedReport &srep,
487158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov                        const StackTrace &trace) {
488158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  for (uptr k = 0; k < ctx->fired_suppressions.Size(); k++) {
489158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
490158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov      continue;
491158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    for (uptr j = 0; j < trace.Size(); j++) {
492158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov      if (trace.Get(j) == ctx->fired_suppressions[k].pc)
493158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov        return true;
494158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    }
495158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  }
496158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  return false;
497158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov}
498158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov
4992f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanybool FrameIsInternal(const ReportStack *frame) {
5002f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return frame != 0 && frame->file != 0
5012f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany      && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
5022f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany          internal_strstr(frame->file, "sanitizer_common_interceptors.inc"));
5032f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
5042f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
505543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov// On programs that use Java we see weird reports like:
506543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov// WARNING: ThreadSanitizer: data race (pid=22512)
507543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//   Read of size 8 at 0x7d2b00084318 by thread 100:
508543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #0 memcpy tsan_interceptors.cc:406 (foo+0x00000d8dfae3)
509543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #1 <null> <null>:0 (0x7f7ad9b40193)
510543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//   Previous write of size 8 at 0x7d2b00084318 by thread 105:
511543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
512543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov//     #1 <null> <null>:0 (0x7f7ad9b42707)
513543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukovstatic bool IsJavaNonsense(const ReportDesc *rep) {
514543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  for (uptr i = 0; i < rep->mops.Size(); i++) {
515543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    ReportMop *mop = rep->mops[i];
516543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    ReportStack *frame = mop->stack;
517e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov    if (frame == 0
518e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov        || (frame->func == 0 && frame->file == 0 && frame->line == 0
519e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov          && frame->module == 0)) {
520e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov      return true;
521e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov    }
5222f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    if (FrameIsInternal(frame)) {
523543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov      frame = frame->next;
524543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov      if (frame == 0
525543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov          || (frame->func == 0 && frame->file == 0 && frame->line == 0
526543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov            && frame->module == 0)) {
527543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov        if (frame) {
528543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov          FiredSuppression supp = {rep->typ, frame->pc};
529543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov          CTX()->fired_suppressions.PushBack(supp);
530543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov        }
531543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov        return true;
532543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov      }
533543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    }
534543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  }
535543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  return false;
536543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov}
537543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov
5383285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukovstatic bool RaceBetweenAtomicAndFree(ThreadState *thr) {
5393285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  Shadow s0(thr->racy_state[0]);
5403285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  Shadow s1(thr->racy_state[1]);
5413285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
5423285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (!s0.IsAtomic() && !s1.IsAtomic())
5433285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
5443285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (s0.IsAtomic() && s1.IsFreed())
5453285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
5463285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (s1.IsAtomic() && thr->is_freeing)
5473285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return true;
5483285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  return false;
5493285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov}
5503285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov
5517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ReportRace(ThreadState *thr) {
5528a326776e41dc68c810ba3719a24328de517d8f9Dmitry Vyukov  if (!flags()->report_bugs)
5538a326776e41dc68c810ba3719a24328de517d8f9Dmitry Vyukov    return;
5547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ScopedInRtl in_rtl;
555069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov
5563285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
5573285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov    return;
5583285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov
55911edbbbbf96c11da65bb6e9a2dde303f4bdfde7dDmitry Vyukov  if (thr->in_signal_handler)
56011edbbbbf96c11da65bb6e9a2dde303f4bdfde7dDmitry Vyukov    Printf("ThreadSanitizer: printing report from signal handler."
56111edbbbbf96c11da65bb6e9a2dde303f4bdfde7dDmitry Vyukov           " Can crash or hang.\n");
56211edbbbbf96c11da65bb6e9a2dde303f4bdfde7dDmitry Vyukov
563069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  bool freed = false;
564069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  {
565069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    Shadow s(thr->racy_state[1]);
566069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    freed = s.GetFreedAndReset();
567069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov    thr->racy_state[1] = s.raw();
568069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  }
569069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov
5707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr);
5717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr_min = 0;
5727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr addr_max = 0;
5737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
5747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr a0 = addr + Shadow(thr->racy_state[0]).addr0();
5757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr a1 = addr + Shadow(thr->racy_state[1]).addr0();
5767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr e0 = a0 + Shadow(thr->racy_state[0]).size();
5777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    uptr e1 = a1 + Shadow(thr->racy_state[1]).size();
5787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr_min = min(a0, a1);
5797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr_max = max(e0, e1);
5807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (IsExpectedReport(addr_min, addr_max - addr_min))
5817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      return;
5827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
5837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Context *ctx = CTX();
5857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Lock l0(&ctx->thread_mtx);
5867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
587069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace);
588069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  const uptr kMop = 2;
589069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  StackTrace traces[kMop];
590385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  const uptr toppc = TraceTopPC(thr);
591158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  traces[0].ObtainCurrent(thr, toppc);
592158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  if (IsFiredSuppression(ctx, rep, traces[0]))
593158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov    return;
594ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  InternalScopedBuffer<MutexSet> mset2(1);
595ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  new(mset2.data()) MutexSet();
596158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  Shadow s2(thr->racy_state[1]);
597ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
5987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (HandleRacyStacks(thr, traces, addr_min, addr_max))
6007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
6017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
602069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  for (uptr i = 0; i < kMop; i++) {
6037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Shadow s(thr->racy_state[i]);
604ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    rep.AddMemoryAccess(addr, s, &traces[i],
605ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov                        i == 0 ? &thr->mset : mset2.data());
6067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
6077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
608543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov  if (flags()->suppress_java && IsJavaNonsense(rep.GetReport()))
609543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov    return;
610543b94a5cd102c0795b44d78234d5458eed2c75eDmitry Vyukov
611069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  for (uptr i = 0; i < kMop; i++) {
6127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    FastState s(thr->racy_state[i]);
6137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ThreadContext *tctx = ctx->threads[s.tid()];
6147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1)
6157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      continue;
6167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    rep.AddThread(tctx);
6177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
6187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
619ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  rep.AddLocation(addr_min, addr_max - addr_min);
620ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov
621848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov#ifndef TSAN_GO
622848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  {  // NOLINT
623848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    Shadow s(thr->racy_state[1]);
624848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    if (s.epoch() <= thr->last_sleep_clock.get(s.tid()))
625848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov      rep.AddSleep(thr->last_sleep_stack_id);
626848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  }
627848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov#endif
628848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
629e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov  if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
630e5e3a13b43beee99a0d3ec888a0be170a53af934Dmitry Vyukov                              rep.GetReport()->mops[1]->stack))
6317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
6327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  AddRacyStacks(thr, traces, addr_min, addr_max);
6347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
6357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6361da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintCurrentStack(ThreadState *thr, uptr pc) {
6371da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  StackTrace trace;
6381da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  trace.ObtainCurrent(thr, pc);
6391da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov  PrintStack(SymbolizeStack(trace));
6401da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov}
6411da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukov
642793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukovvoid PrintCurrentStackSlow() {
643793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov#ifndef TSAN_GO
644793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
645793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov      sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
646793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
647793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov      kStackTraceMax);
648793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  StackTrace trace;
649793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  trace.Init(ptrace->trace, ptrace->size);
650793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov  PrintStack(SymbolizeStack(trace));
651793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov#endif
652793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov}
653793e7610934531fa014aa2c0721d7901bdbae548Dmitry Vyukov
6547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
655