tsan_rtl_mutex.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
1//===-- tsan_rtl_mutex.cc -------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13
14#include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
15#include <sanitizer_common/sanitizer_stackdepot.h>
16
17#include "tsan_rtl.h"
18#include "tsan_flags.h"
19#include "tsan_sync.h"
20#include "tsan_report.h"
21#include "tsan_symbolize.h"
22#include "tsan_platform.h"
23
24namespace __tsan {
25
26void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r);
27
28struct Callback : DDCallback {
29  ThreadState *thr;
30  uptr pc;
31
32  Callback(ThreadState *thr, uptr pc)
33      : thr(thr)
34      , pc(pc) {
35    DDCallback::pt = thr->dd_pt;
36    DDCallback::lt = thr->dd_lt;
37  }
38
39  virtual u32 Unwind() {
40    return CurrentStackId(thr, pc);
41  }
42  virtual int UniqueTid() {
43    return thr->unique_id;
44  }
45};
46
47void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
48  Callback cb(thr, pc);
49  ctx->dd->MutexInit(&cb, &s->dd);
50  s->dd.ctx = s->GetId();
51}
52
53static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
54    uptr addr, u64 mid) {
55  // In Go, these misuses are either impossible, or detected by std lib,
56  // or false positives (e.g. unlock in a different thread).
57  if (kGoMode)
58    return;
59  ThreadRegistryLock l(ctx->thread_registry);
60  ScopedReport rep(typ);
61  rep.AddMutex(mid);
62  StackTrace trace;
63  trace.ObtainCurrent(thr, pc);
64  rep.AddStack(&trace, true);
65  rep.AddLocation(addr, 1);
66  OutputReport(thr, rep);
67}
68
69void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
70                 bool rw, bool recursive, bool linker_init) {
71  DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
72  StatInc(thr, StatMutexCreate);
73  if (!linker_init && IsAppMem(addr)) {
74    CHECK(!thr->is_freeing);
75    thr->is_freeing = true;
76    MemoryWrite(thr, pc, addr, kSizeLog1);
77    thr->is_freeing = false;
78  }
79  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
80  s->is_rw = rw;
81  s->is_recursive = recursive;
82  s->is_linker_init = linker_init;
83  if (kCppMode && s->creation_stack_id == 0)
84    s->creation_stack_id = CurrentStackId(thr, pc);
85  s->mtx.Unlock();
86}
87
88void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
89  DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
90  StatInc(thr, StatMutexDestroy);
91#ifndef TSAN_GO
92  // Global mutexes not marked as LINKER_INITIALIZED
93  // cause tons of not interesting reports, so just ignore it.
94  if (IsGlobalVar(addr))
95    return;
96#endif
97  if (IsAppMem(addr)) {
98    CHECK(!thr->is_freeing);
99    thr->is_freeing = true;
100    MemoryWrite(thr, pc, addr, kSizeLog1);
101    thr->is_freeing = false;
102  }
103  SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
104  if (s == 0)
105    return;
106  if (flags()->detect_deadlocks) {
107    Callback cb(thr, pc);
108    ctx->dd->MutexDestroy(&cb, &s->dd);
109    ctx->dd->MutexInit(&cb, &s->dd);
110  }
111  bool unlock_locked = false;
112  if (flags()->report_destroy_locked
113      && s->owner_tid != SyncVar::kInvalidTid
114      && !s->is_broken) {
115    s->is_broken = true;
116    unlock_locked = true;
117  }
118  u64 mid = s->GetId();
119  u32 last_lock = s->last_lock;
120  if (!unlock_locked)
121    s->Reset();  // must not reset it before the report is printed
122  s->mtx.Unlock();
123  if (unlock_locked) {
124    ThreadRegistryLock l(ctx->thread_registry);
125    ScopedReport rep(ReportTypeMutexDestroyLocked);
126    rep.AddMutex(mid);
127    StackTrace trace;
128    trace.ObtainCurrent(thr, pc);
129    rep.AddStack(&trace);
130    FastState last(last_lock);
131    RestoreStack(last.tid(), last.epoch(), &trace, 0);
132    rep.AddStack(&trace, true);
133    rep.AddLocation(addr, 1);
134    OutputReport(thr, rep);
135  }
136  if (unlock_locked) {
137    SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
138    if (s != 0) {
139      s->Reset();
140      s->mtx.Unlock();
141    }
142  }
143  thr->mset.Remove(mid);
144  // s will be destroyed and freed in MetaMap::FreeBlock.
145}
146
147void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
148  DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
149  CHECK_GT(rec, 0);
150  if (IsAppMem(addr))
151    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
152  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
153  thr->fast_state.IncrementEpoch();
154  TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
155  bool report_double_lock = false;
156  if (s->owner_tid == SyncVar::kInvalidTid) {
157    CHECK_EQ(s->recursion, 0);
158    s->owner_tid = thr->tid;
159    s->last_lock = thr->fast_state.raw();
160  } else if (s->owner_tid == thr->tid) {
161    CHECK_GT(s->recursion, 0);
162  } else if (flags()->report_mutex_bugs && !s->is_broken) {
163    s->is_broken = true;
164    report_double_lock = true;
165  }
166  if (s->recursion == 0) {
167    StatInc(thr, StatMutexLock);
168    AcquireImpl(thr, pc, &s->clock);
169    AcquireImpl(thr, pc, &s->read_clock);
170  } else if (!s->is_recursive) {
171    StatInc(thr, StatMutexRecLock);
172  }
173  s->recursion += rec;
174  thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
175  if (flags()->detect_deadlocks && (s->recursion - rec) == 0) {
176    Callback cb(thr, pc);
177    if (!try_lock)
178      ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
179    ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
180  }
181  u64 mid = s->GetId();
182  s->mtx.Unlock();
183  // Can't touch s after this point.
184  if (report_double_lock)
185    ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
186  if (flags()->detect_deadlocks) {
187    Callback cb(thr, pc);
188    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
189  }
190}
191
192int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
193  DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
194  if (IsAppMem(addr))
195    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
196  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
197  thr->fast_state.IncrementEpoch();
198  TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
199  int rec = 0;
200  bool report_bad_unlock = false;
201  if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) {
202    if (flags()->report_mutex_bugs && !s->is_broken) {
203      s->is_broken = true;
204      report_bad_unlock = true;
205    }
206  } else {
207    rec = all ? s->recursion : 1;
208    s->recursion -= rec;
209    if (s->recursion == 0) {
210      StatInc(thr, StatMutexUnlock);
211      s->owner_tid = SyncVar::kInvalidTid;
212      ReleaseStoreImpl(thr, pc, &s->clock);
213    } else {
214      StatInc(thr, StatMutexRecUnlock);
215    }
216  }
217  thr->mset.Del(s->GetId(), true);
218  if (flags()->detect_deadlocks && s->recursion == 0 && !report_bad_unlock) {
219    Callback cb(thr, pc);
220    ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
221  }
222  u64 mid = s->GetId();
223  s->mtx.Unlock();
224  // Can't touch s after this point.
225  if (report_bad_unlock)
226    ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
227  if (flags()->detect_deadlocks && !report_bad_unlock) {
228    Callback cb(thr, pc);
229    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
230  }
231  return rec;
232}
233
234void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
235  DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
236  StatInc(thr, StatMutexReadLock);
237  if (IsAppMem(addr))
238    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
239  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
240  thr->fast_state.IncrementEpoch();
241  TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
242  bool report_bad_lock = false;
243  if (s->owner_tid != SyncVar::kInvalidTid) {
244    if (flags()->report_mutex_bugs && !s->is_broken) {
245      s->is_broken = true;
246      report_bad_lock = true;
247    }
248  }
249  AcquireImpl(thr, pc, &s->clock);
250  s->last_lock = thr->fast_state.raw();
251  thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
252  if (flags()->detect_deadlocks && s->recursion == 0) {
253    Callback cb(thr, pc);
254    if (!trylock)
255      ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
256    ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
257  }
258  u64 mid = s->GetId();
259  s->mtx.ReadUnlock();
260  // Can't touch s after this point.
261  if (report_bad_lock)
262    ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
263  if (flags()->detect_deadlocks) {
264    Callback cb(thr, pc);
265    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
266  }
267}
268
269void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
270  DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
271  StatInc(thr, StatMutexReadUnlock);
272  if (IsAppMem(addr))
273    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
274  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
275  thr->fast_state.IncrementEpoch();
276  TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
277  bool report_bad_unlock = false;
278  if (s->owner_tid != SyncVar::kInvalidTid) {
279    if (flags()->report_mutex_bugs && !s->is_broken) {
280      s->is_broken = true;
281      report_bad_unlock = true;
282    }
283  }
284  ReleaseImpl(thr, pc, &s->read_clock);
285  if (flags()->detect_deadlocks && s->recursion == 0) {
286    Callback cb(thr, pc);
287    ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
288  }
289  u64 mid = s->GetId();
290  s->mtx.Unlock();
291  // Can't touch s after this point.
292  thr->mset.Del(mid, false);
293  if (report_bad_unlock)
294    ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
295  if (flags()->detect_deadlocks) {
296    Callback cb(thr, pc);
297    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
298  }
299}
300
301void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
302  DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
303  if (IsAppMem(addr))
304    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
305  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
306  bool write = true;
307  bool report_bad_unlock = false;
308  if (s->owner_tid == SyncVar::kInvalidTid) {
309    // Seems to be read unlock.
310    write = false;
311    StatInc(thr, StatMutexReadUnlock);
312    thr->fast_state.IncrementEpoch();
313    TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
314    ReleaseImpl(thr, pc, &s->read_clock);
315  } else if (s->owner_tid == thr->tid) {
316    // Seems to be write unlock.
317    thr->fast_state.IncrementEpoch();
318    TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
319    CHECK_GT(s->recursion, 0);
320    s->recursion--;
321    if (s->recursion == 0) {
322      StatInc(thr, StatMutexUnlock);
323      s->owner_tid = SyncVar::kInvalidTid;
324      ReleaseImpl(thr, pc, &s->clock);
325    } else {
326      StatInc(thr, StatMutexRecUnlock);
327    }
328  } else if (!s->is_broken) {
329    s->is_broken = true;
330    report_bad_unlock = true;
331  }
332  thr->mset.Del(s->GetId(), write);
333  if (flags()->detect_deadlocks && s->recursion == 0) {
334    Callback cb(thr, pc);
335    ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
336  }
337  u64 mid = s->GetId();
338  s->mtx.Unlock();
339  // Can't touch s after this point.
340  if (report_bad_unlock)
341    ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
342  if (flags()->detect_deadlocks) {
343    Callback cb(thr, pc);
344    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
345  }
346}
347
348void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
349  DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
350  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
351  s->owner_tid = SyncVar::kInvalidTid;
352  s->recursion = 0;
353  s->mtx.Unlock();
354}
355
356void Acquire(ThreadState *thr, uptr pc, uptr addr) {
357  DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
358  if (thr->ignore_sync)
359    return;
360  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
361  AcquireImpl(thr, pc, &s->clock);
362  s->mtx.ReadUnlock();
363}
364
365static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
366  ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
367  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
368  if (tctx->status == ThreadStatusRunning)
369    thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch());
370  else
371    thr->clock.set(tctx->tid, tctx->epoch1);
372}
373
374void AcquireGlobal(ThreadState *thr, uptr pc) {
375  DPrintf("#%d: AcquireGlobal\n", thr->tid);
376  if (thr->ignore_sync)
377    return;
378  ThreadRegistryLock l(ctx->thread_registry);
379  ctx->thread_registry->RunCallbackForEachThreadLocked(
380      UpdateClockCallback, thr);
381}
382
383void Release(ThreadState *thr, uptr pc, uptr addr) {
384  DPrintf("#%d: Release %zx\n", thr->tid, addr);
385  if (thr->ignore_sync)
386    return;
387  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
388  thr->fast_state.IncrementEpoch();
389  // Can't increment epoch w/o writing to the trace as well.
390  TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
391  ReleaseImpl(thr, pc, &s->clock);
392  s->mtx.Unlock();
393}
394
395void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
396  DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
397  if (thr->ignore_sync)
398    return;
399  SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
400  thr->fast_state.IncrementEpoch();
401  // Can't increment epoch w/o writing to the trace as well.
402  TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
403  ReleaseStoreImpl(thr, pc, &s->clock);
404  s->mtx.Unlock();
405}
406
407#ifndef TSAN_GO
408static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
409  ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
410  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
411  if (tctx->status == ThreadStatusRunning)
412    thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch());
413  else
414    thr->last_sleep_clock.set(tctx->tid, tctx->epoch1);
415}
416
417void AfterSleep(ThreadState *thr, uptr pc) {
418  DPrintf("#%d: AfterSleep %zx\n", thr->tid);
419  if (thr->ignore_sync)
420    return;
421  thr->last_sleep_stack_id = CurrentStackId(thr, pc);
422  ThreadRegistryLock l(ctx->thread_registry);
423  ctx->thread_registry->RunCallbackForEachThreadLocked(
424      UpdateSleepClockCallback, thr);
425}
426#endif
427
428void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
429  if (thr->ignore_sync)
430    return;
431  thr->clock.set(thr->fast_state.epoch());
432  thr->clock.acquire(c);
433  StatInc(thr, StatSyncAcquire);
434}
435
436void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
437  if (thr->ignore_sync)
438    return;
439  thr->clock.set(thr->fast_state.epoch());
440  thr->fast_synch_epoch = thr->fast_state.epoch();
441  thr->clock.release(c);
442  StatInc(thr, StatSyncRelease);
443}
444
445void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
446  if (thr->ignore_sync)
447    return;
448  thr->clock.set(thr->fast_state.epoch());
449  thr->fast_synch_epoch = thr->fast_state.epoch();
450  thr->clock.ReleaseStore(c);
451  StatInc(thr, StatSyncRelease);
452}
453
454void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
455  if (thr->ignore_sync)
456    return;
457  thr->clock.set(thr->fast_state.epoch());
458  thr->fast_synch_epoch = thr->fast_state.epoch();
459  thr->clock.acq_rel(c);
460  StatInc(thr, StatSyncAcquire);
461  StatInc(thr, StatSyncRelease);
462}
463
464void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
465  if (r == 0)
466    return;
467  ThreadRegistryLock l(ctx->thread_registry);
468  ScopedReport rep(ReportTypeDeadlock);
469  for (int i = 0; i < r->n; i++) {
470    rep.AddMutex(r->loop[i].mtx_ctx0);
471    rep.AddUniqueTid((int)r->loop[i].thr_ctx);
472    rep.AddThread((int)r->loop[i].thr_ctx);
473  }
474  InternalScopedBuffer<StackTrace> stacks(2 * DDReport::kMaxLoopSize);
475  uptr dummy_pc = 0x42;
476  for (int i = 0; i < r->n; i++) {
477    uptr size;
478    for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
479      u32 stk = r->loop[i].stk[j];
480      if (stk) {
481        const uptr *trace = StackDepotGet(stk, &size);
482        stacks[i].Init(const_cast<uptr *>(trace), size);
483      } else {
484        // Sometimes we fail to extract the stack trace (FIXME: investigate),
485        // but we should still produce some stack trace in the report.
486        stacks[i].Init(&dummy_pc, 1);
487      }
488      rep.AddStack(&stacks[i], true);
489    }
490  }
491  OutputReport(thr, rep);
492}
493
494}  // namespace __tsan
495