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