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