dd_rtl.cpp revision 360784
1//===-- dd_rtl.cpp --------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "dd_rtl.h"
10#include "sanitizer_common/sanitizer_common.h"
11#include "sanitizer_common/sanitizer_placement_new.h"
12#include "sanitizer_common/sanitizer_flags.h"
13#include "sanitizer_common/sanitizer_flag_parser.h"
14#include "sanitizer_common/sanitizer_stacktrace.h"
15#include "sanitizer_common/sanitizer_stackdepot.h"
16
17namespace __dsan {
18
19static Context *ctx;
20
21static u32 CurrentStackTrace(Thread *thr, uptr skip) {
22  BufferedStackTrace stack;
23  thr->ignore_interceptors = true;
24  stack.Unwind(1000, 0, 0, 0, 0, 0, false);
25  thr->ignore_interceptors = false;
26  if (stack.size <= skip)
27    return 0;
28  return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
29}
30
31static void PrintStackTrace(Thread *thr, u32 stk) {
32  StackTrace stack = StackDepotGet(stk);
33  thr->ignore_interceptors = true;
34  stack.Print();
35  thr->ignore_interceptors = false;
36}
37
38static void ReportDeadlock(Thread *thr, DDReport *rep) {
39  if (rep == 0)
40    return;
41  BlockingMutexLock lock(&ctx->report_mutex);
42  Printf("==============================\n");
43  Printf("WARNING: lock-order-inversion (potential deadlock)\n");
44  for (int i = 0; i < rep->n; i++) {
45    Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
46      rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
47    PrintStackTrace(thr, rep->loop[i].stk[1]);
48    if (rep->loop[i].stk[0]) {
49      Printf("Mutex %llu was acquired here:\n",
50        rep->loop[i].mtx_ctx0);
51      PrintStackTrace(thr, rep->loop[i].stk[0]);
52    }
53  }
54  Printf("==============================\n");
55}
56
57Callback::Callback(Thread *thr)
58    : thr(thr) {
59  lt = thr->dd_lt;
60  pt = thr->dd_pt;
61}
62
63u32 Callback::Unwind() {
64  return CurrentStackTrace(thr, 3);
65}
66
67static void InitializeFlags() {
68  Flags *f = flags();
69
70  // Default values.
71  f->second_deadlock_stack = false;
72
73  SetCommonFlagsDefaults();
74  {
75    // Override some common flags defaults.
76    CommonFlags cf;
77    cf.CopyFrom(*common_flags());
78    cf.allow_addr2line = true;
79    OverrideCommonFlags(cf);
80  }
81
82  // Override from command line.
83  FlagParser parser;
84  RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
85  RegisterCommonFlags(&parser);
86  parser.ParseStringFromEnv("DSAN_OPTIONS");
87  SetVerbosity(common_flags()->verbosity);
88}
89
90void Initialize() {
91  static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
92  ctx = new(ctx_mem) Context();
93
94  InitializeInterceptors();
95  InitializeFlags();
96  ctx->dd = DDetector::Create(flags());
97}
98
99void ThreadInit(Thread *thr) {
100  static atomic_uintptr_t id_gen;
101  uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
102  thr->dd_pt = ctx->dd->CreatePhysicalThread();
103  thr->dd_lt = ctx->dd->CreateLogicalThread(id);
104}
105
106void ThreadDestroy(Thread *thr) {
107  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
108  ctx->dd->DestroyLogicalThread(thr->dd_lt);
109}
110
111void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
112  if (thr->ignore_interceptors)
113    return;
114  Callback cb(thr);
115  {
116    MutexHashMap::Handle h(&ctx->mutex_map, m);
117    if (h.created())
118      ctx->dd->MutexInit(&cb, &h->dd);
119    ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
120  }
121  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
122}
123
124void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
125  if (thr->ignore_interceptors)
126    return;
127  Callback cb(thr);
128  {
129    MutexHashMap::Handle h(&ctx->mutex_map, m);
130    if (h.created())
131      ctx->dd->MutexInit(&cb, &h->dd);
132    ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
133  }
134  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
135}
136
137void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
138  if (thr->ignore_interceptors)
139    return;
140  Callback cb(thr);
141  {
142    MutexHashMap::Handle h(&ctx->mutex_map, m);
143    ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
144  }
145  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
146}
147
148void MutexDestroy(Thread *thr, uptr m) {
149  if (thr->ignore_interceptors)
150    return;
151  Callback cb(thr);
152  MutexHashMap::Handle h(&ctx->mutex_map, m, true);
153  if (!h.exists())
154    return;
155  ctx->dd->MutexDestroy(&cb, &h->dd);
156}
157
158}  // namespace __dsan
159