1//===-- tsan_interface_ann.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// This file is a part of ThreadSanitizer (TSan), a race detector.
10//
11//===----------------------------------------------------------------------===//
12#include "sanitizer_common/sanitizer_libc.h"
13#include "sanitizer_common/sanitizer_internal_defs.h"
14#include "sanitizer_common/sanitizer_placement_new.h"
15#include "sanitizer_common/sanitizer_stacktrace.h"
16#include "sanitizer_common/sanitizer_vector.h"
17#include "tsan_interface_ann.h"
18#include "tsan_report.h"
19#include "tsan_rtl.h"
20#include "tsan_mman.h"
21#include "tsan_flags.h"
22#include "tsan_platform.h"
23
24#define CALLERPC ((uptr)__builtin_return_address(0))
25
26using namespace __tsan;
27
28namespace __tsan {
29
30class ScopedAnnotation {
31 public:
32  ScopedAnnotation(ThreadState *thr, const char *aname, uptr pc)
33      : thr_(thr) {
34    FuncEntry(thr_, pc);
35    DPrintf("#%d: annotation %s()\n", thr_->tid, aname);
36  }
37
38  ~ScopedAnnotation() {
39    FuncExit(thr_);
40    CheckedMutex::CheckNoLocks();
41  }
42 private:
43  ThreadState *const thr_;
44};
45
46#define SCOPED_ANNOTATION_RET(typ, ret)                     \
47  if (!flags()->enable_annotations)                         \
48    return ret;                                             \
49  ThreadState *thr = cur_thread();                          \
50  const uptr caller_pc = (uptr)__builtin_return_address(0); \
51  ScopedAnnotation sa(thr, __func__, caller_pc);            \
52  const uptr pc = StackTrace::GetCurrentPc();               \
53  (void)pc;
54
55#define SCOPED_ANNOTATION(typ) SCOPED_ANNOTATION_RET(typ, )
56
57static const int kMaxDescLen = 128;
58
59struct ExpectRace {
60  ExpectRace *next;
61  ExpectRace *prev;
62  atomic_uintptr_t hitcount;
63  atomic_uintptr_t addcount;
64  uptr addr;
65  uptr size;
66  char *file;
67  int line;
68  char desc[kMaxDescLen];
69};
70
71struct DynamicAnnContext {
72  Mutex mtx;
73  ExpectRace benign;
74
75  DynamicAnnContext() : mtx(MutexTypeAnnotations) {}
76};
77
78static DynamicAnnContext *dyn_ann_ctx;
79static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64);
80
81static void AddExpectRace(ExpectRace *list,
82    char *f, int l, uptr addr, uptr size, char *desc) {
83  ExpectRace *race = list->next;
84  for (; race != list; race = race->next) {
85    if (race->addr == addr && race->size == size) {
86      atomic_store_relaxed(&race->addcount,
87          atomic_load_relaxed(&race->addcount) + 1);
88      return;
89    }
90  }
91  race = static_cast<ExpectRace *>(Alloc(sizeof(ExpectRace)));
92  race->addr = addr;
93  race->size = size;
94  race->file = f;
95  race->line = l;
96  race->desc[0] = 0;
97  atomic_store_relaxed(&race->hitcount, 0);
98  atomic_store_relaxed(&race->addcount, 1);
99  if (desc) {
100    int i = 0;
101    for (; i < kMaxDescLen - 1 && desc[i]; i++)
102      race->desc[i] = desc[i];
103    race->desc[i] = 0;
104  }
105  race->prev = list;
106  race->next = list->next;
107  race->next->prev = race;
108  list->next = race;
109}
110
111static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {
112  for (ExpectRace *race = list->next; race != list; race = race->next) {
113    uptr maxbegin = max(race->addr, addr);
114    uptr minend = min(race->addr + race->size, addr + size);
115    if (maxbegin < minend)
116      return race;
117  }
118  return 0;
119}
120
121static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
122  ExpectRace *race = FindRace(list, addr, size);
123  if (race == 0)
124    return false;
125  DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
126      race->desc, race->addr, (int)race->size, race->file, race->line);
127  atomic_fetch_add(&race->hitcount, 1, memory_order_relaxed);
128  return true;
129}
130
131static void InitList(ExpectRace *list) {
132  list->next = list;
133  list->prev = list;
134}
135
136void InitializeDynamicAnnotations() {
137  dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext;
138  InitList(&dyn_ann_ctx->benign);
139}
140
141bool IsExpectedReport(uptr addr, uptr size) {
142  ReadLock lock(&dyn_ann_ctx->mtx);
143  return CheckContains(&dyn_ann_ctx->benign, addr, size);
144}
145}  // namespace __tsan
146
147using namespace __tsan;
148
149extern "C" {
150void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {
151  SCOPED_ANNOTATION(AnnotateHappensBefore);
152  Release(thr, pc, addr);
153}
154
155void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {
156  SCOPED_ANNOTATION(AnnotateHappensAfter);
157  Acquire(thr, pc, addr);
158}
159
160void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {
161}
162
163void INTERFACE_ATTRIBUTE AnnotateCondVarSignalAll(char *f, int l, uptr cv) {
164}
165
166void INTERFACE_ATTRIBUTE AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {
167}
168
169void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv,
170                                             uptr lock) {
171}
172
173void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) {
174  SCOPED_ANNOTATION(AnnotateRWLockCreate);
175  MutexCreate(thr, pc, m, MutexFlagWriteReentrant);
176}
177
178void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) {
179  SCOPED_ANNOTATION(AnnotateRWLockCreateStatic);
180  MutexCreate(thr, pc, m, MutexFlagWriteReentrant | MutexFlagLinkerInit);
181}
182
183void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) {
184  SCOPED_ANNOTATION(AnnotateRWLockDestroy);
185  MutexDestroy(thr, pc, m);
186}
187
188void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m,
189                                                uptr is_w) {
190  SCOPED_ANNOTATION(AnnotateRWLockAcquired);
191  if (is_w)
192    MutexPostLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);
193  else
194    MutexPostReadLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);
195}
196
197void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m,
198                                                uptr is_w) {
199  SCOPED_ANNOTATION(AnnotateRWLockReleased);
200  if (is_w)
201    MutexUnlock(thr, pc, m);
202  else
203    MutexReadUnlock(thr, pc, m);
204}
205
206void INTERFACE_ATTRIBUTE AnnotateTraceMemory(char *f, int l, uptr mem) {
207}
208
209void INTERFACE_ATTRIBUTE AnnotateFlushState(char *f, int l) {
210}
211
212void INTERFACE_ATTRIBUTE AnnotateNewMemory(char *f, int l, uptr mem,
213                                           uptr size) {
214}
215
216void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) {
217}
218
219void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
220}
221
222void INTERFACE_ATTRIBUTE AnnotateEnableRaceDetection(
223    char *f, int l, int enable) {
224}
225
226void INTERFACE_ATTRIBUTE AnnotateMutexIsUsedAsCondVar(
227    char *f, int l, uptr mu) {
228}
229
230void INTERFACE_ATTRIBUTE AnnotatePCQGet(
231    char *f, int l, uptr pcq) {
232}
233
234void INTERFACE_ATTRIBUTE AnnotatePCQPut(
235    char *f, int l, uptr pcq) {
236}
237
238void INTERFACE_ATTRIBUTE AnnotatePCQDestroy(
239    char *f, int l, uptr pcq) {
240}
241
242void INTERFACE_ATTRIBUTE AnnotatePCQCreate(
243    char *f, int l, uptr pcq) {
244}
245
246void INTERFACE_ATTRIBUTE AnnotateExpectRace(
247    char *f, int l, uptr mem, char *desc) {
248}
249
250static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {
251  Lock lock(&dyn_ann_ctx->mtx);
252  AddExpectRace(&dyn_ann_ctx->benign,
253                f, l, mem, size, desc);
254  DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l);
255}
256
257void INTERFACE_ATTRIBUTE AnnotateBenignRaceSized(
258    char *f, int l, uptr mem, uptr size, char *desc) {
259  SCOPED_ANNOTATION(AnnotateBenignRaceSized);
260  BenignRaceImpl(f, l, mem, size, desc);
261}
262
263void INTERFACE_ATTRIBUTE AnnotateBenignRace(
264    char *f, int l, uptr mem, char *desc) {
265  SCOPED_ANNOTATION(AnnotateBenignRace);
266  BenignRaceImpl(f, l, mem, 1, desc);
267}
268
269void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
270  SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
271  ThreadIgnoreBegin(thr, pc);
272}
273
274void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
275  SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
276  ThreadIgnoreEnd(thr);
277}
278
279void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
280  SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
281  ThreadIgnoreBegin(thr, pc);
282}
283
284void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
285  SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
286  ThreadIgnoreEnd(thr);
287}
288
289void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {
290  SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);
291  ThreadIgnoreSyncBegin(thr, pc);
292}
293
294void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {
295  SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);
296  ThreadIgnoreSyncEnd(thr);
297}
298
299void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
300    char *f, int l, uptr addr, uptr size) {
301}
302
303void INTERFACE_ATTRIBUTE AnnotateUnpublishMemoryRange(
304    char *f, int l, uptr addr, uptr size) {
305}
306
307void INTERFACE_ATTRIBUTE AnnotateThreadName(
308    char *f, int l, char *name) {
309  SCOPED_ANNOTATION(AnnotateThreadName);
310  ThreadSetName(thr, name);
311}
312
313// We deliberately omit the implementation of WTFAnnotateHappensBefore() and
314// WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate
315// atomic operations, which should be handled by ThreadSanitizer correctly.
316void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
317}
318
319void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
320}
321
322void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
323    char *f, int l, uptr mem, uptr sz, char *desc) {
324  SCOPED_ANNOTATION(AnnotateBenignRaceSized);
325  BenignRaceImpl(f, l, mem, sz, desc);
326}
327
328int INTERFACE_ATTRIBUTE RunningOnValgrind() {
329  return flags()->running_on_valgrind;
330}
331
332double __attribute__((weak)) INTERFACE_ATTRIBUTE ValgrindSlowdown(void) {
333  return 10.0;
334}
335
336const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
337  if (internal_strcmp(query, "pure_happens_before") == 0)
338    return "1";
339  else
340    return "0";
341}
342
343void INTERFACE_ATTRIBUTE
344AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
345void INTERFACE_ATTRIBUTE
346AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
347
348// Note: the parameter is called flagz, because flags is already taken
349// by the global function that returns flags.
350INTERFACE_ATTRIBUTE
351void __tsan_mutex_create(void *m, unsigned flagz) {
352  SCOPED_ANNOTATION(__tsan_mutex_create);
353  MutexCreate(thr, pc, (uptr)m, flagz & MutexCreationFlagMask);
354}
355
356INTERFACE_ATTRIBUTE
357void __tsan_mutex_destroy(void *m, unsigned flagz) {
358  SCOPED_ANNOTATION(__tsan_mutex_destroy);
359  MutexDestroy(thr, pc, (uptr)m, flagz);
360}
361
362INTERFACE_ATTRIBUTE
363void __tsan_mutex_pre_lock(void *m, unsigned flagz) {
364  SCOPED_ANNOTATION(__tsan_mutex_pre_lock);
365  if (!(flagz & MutexFlagTryLock)) {
366    if (flagz & MutexFlagReadLock)
367      MutexPreReadLock(thr, pc, (uptr)m);
368    else
369      MutexPreLock(thr, pc, (uptr)m);
370  }
371  ThreadIgnoreBegin(thr, 0);
372  ThreadIgnoreSyncBegin(thr, 0);
373}
374
375INTERFACE_ATTRIBUTE
376void __tsan_mutex_post_lock(void *m, unsigned flagz, int rec) {
377  SCOPED_ANNOTATION(__tsan_mutex_post_lock);
378  ThreadIgnoreSyncEnd(thr);
379  ThreadIgnoreEnd(thr);
380  if (!(flagz & MutexFlagTryLockFailed)) {
381    if (flagz & MutexFlagReadLock)
382      MutexPostReadLock(thr, pc, (uptr)m, flagz);
383    else
384      MutexPostLock(thr, pc, (uptr)m, flagz, rec);
385  }
386}
387
388INTERFACE_ATTRIBUTE
389int __tsan_mutex_pre_unlock(void *m, unsigned flagz) {
390  SCOPED_ANNOTATION_RET(__tsan_mutex_pre_unlock, 0);
391  int ret = 0;
392  if (flagz & MutexFlagReadLock) {
393    CHECK(!(flagz & MutexFlagRecursiveUnlock));
394    MutexReadUnlock(thr, pc, (uptr)m);
395  } else {
396    ret = MutexUnlock(thr, pc, (uptr)m, flagz);
397  }
398  ThreadIgnoreBegin(thr, 0);
399  ThreadIgnoreSyncBegin(thr, 0);
400  return ret;
401}
402
403INTERFACE_ATTRIBUTE
404void __tsan_mutex_post_unlock(void *m, unsigned flagz) {
405  SCOPED_ANNOTATION(__tsan_mutex_post_unlock);
406  ThreadIgnoreSyncEnd(thr);
407  ThreadIgnoreEnd(thr);
408}
409
410INTERFACE_ATTRIBUTE
411void __tsan_mutex_pre_signal(void *addr, unsigned flagz) {
412  SCOPED_ANNOTATION(__tsan_mutex_pre_signal);
413  ThreadIgnoreBegin(thr, 0);
414  ThreadIgnoreSyncBegin(thr, 0);
415}
416
417INTERFACE_ATTRIBUTE
418void __tsan_mutex_post_signal(void *addr, unsigned flagz) {
419  SCOPED_ANNOTATION(__tsan_mutex_post_signal);
420  ThreadIgnoreSyncEnd(thr);
421  ThreadIgnoreEnd(thr);
422}
423
424INTERFACE_ATTRIBUTE
425void __tsan_mutex_pre_divert(void *addr, unsigned flagz) {
426  SCOPED_ANNOTATION(__tsan_mutex_pre_divert);
427  // Exit from ignore region started in __tsan_mutex_pre_lock/unlock/signal.
428  ThreadIgnoreSyncEnd(thr);
429  ThreadIgnoreEnd(thr);
430}
431
432INTERFACE_ATTRIBUTE
433void __tsan_mutex_post_divert(void *addr, unsigned flagz) {
434  SCOPED_ANNOTATION(__tsan_mutex_post_divert);
435  ThreadIgnoreBegin(thr, 0);
436  ThreadIgnoreSyncBegin(thr, 0);
437}
438
439static void ReportMutexHeldWrongContext(ThreadState *thr, uptr pc) {
440  ThreadRegistryLock l(&ctx->thread_registry);
441  ScopedReport rep(ReportTypeMutexHeldWrongContext);
442  for (uptr i = 0; i < thr->mset.Size(); ++i) {
443    MutexSet::Desc desc = thr->mset.Get(i);
444    rep.AddMutex(desc.addr, desc.stack_id);
445  }
446  VarSizeStackTrace trace;
447  ObtainCurrentStack(thr, pc, &trace);
448  rep.AddStack(trace, true);
449  OutputReport(thr, rep);
450}
451
452INTERFACE_ATTRIBUTE
453void __tsan_check_no_mutexes_held() {
454  SCOPED_ANNOTATION(__tsan_check_no_mutexes_held);
455  if (thr->mset.Size() == 0) {
456    return;
457  }
458  ReportMutexHeldWrongContext(thr, pc);
459}
460}  // extern "C"
461