]>
Commit | Line | Data |
---|---|---|
cd0be65c WM |
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_placement_new.h" | |
13 | #include "tsan_interface_ann.h" | |
14 | #include "tsan_mutex.h" | |
15 | #include "tsan_report.h" | |
16 | #include "tsan_rtl.h" | |
17 | #include "tsan_mman.h" | |
18 | #include "tsan_flags.h" | |
19 | #include "tsan_platform.h" | |
20 | ||
21 | #define CALLERPC ((uptr)__builtin_return_address(0)) | |
22 | ||
23 | using namespace __tsan; // NOLINT | |
24 | ||
25 | namespace __tsan { | |
26 | ||
27 | class ScopedAnnotation { | |
28 | public: | |
29 | ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l, | |
30 | uptr pc) | |
31 | : thr_(thr) | |
32 | , in_rtl_(thr->in_rtl) { | |
33 | CHECK_EQ(thr_->in_rtl, 0); | |
34 | FuncEntry(thr_, pc); | |
35 | thr_->in_rtl++; | |
36 | DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l); | |
37 | } | |
38 | ||
39 | ~ScopedAnnotation() { | |
40 | thr_->in_rtl--; | |
41 | CHECK_EQ(in_rtl_, thr_->in_rtl); | |
42 | FuncExit(thr_); | |
43 | } | |
44 | private: | |
45 | ThreadState *const thr_; | |
46 | const int in_rtl_; | |
47 | }; | |
48 | ||
49 | #define SCOPED_ANNOTATION(typ) \ | |
50 | if (!flags()->enable_annotations) \ | |
51 | return; \ | |
52 | ThreadState *thr = cur_thread(); \ | |
53 | const uptr pc = (uptr)__builtin_return_address(0); \ | |
54 | StatInc(thr, StatAnnotation); \ | |
55 | StatInc(thr, Stat##typ); \ | |
56 | ScopedAnnotation sa(thr, __FUNCTION__, f, l, \ | |
57 | (uptr)__builtin_return_address(0)); \ | |
58 | (void)pc; \ | |
59 | /**/ | |
60 | ||
61 | static const int kMaxDescLen = 128; | |
62 | ||
63 | struct ExpectRace { | |
64 | ExpectRace *next; | |
65 | ExpectRace *prev; | |
66 | int hitcount; | |
67 | uptr addr; | |
68 | uptr size; | |
69 | char *file; | |
70 | int line; | |
71 | char desc[kMaxDescLen]; | |
72 | }; | |
73 | ||
74 | struct DynamicAnnContext { | |
75 | Mutex mtx; | |
76 | ExpectRace expect; | |
77 | ExpectRace benign; | |
78 | ||
79 | DynamicAnnContext() | |
80 | : mtx(MutexTypeAnnotations, StatMtxAnnotations) { | |
81 | } | |
82 | }; | |
83 | ||
84 | static DynamicAnnContext *dyn_ann_ctx; | |
85 | static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64); | |
86 | ||
87 | static void AddExpectRace(ExpectRace *list, | |
88 | char *f, int l, uptr addr, uptr size, char *desc) { | |
89 | ExpectRace *race = list->next; | |
90 | for (; race != list; race = race->next) { | |
91 | if (race->addr == addr && race->size == size) | |
92 | return; | |
93 | } | |
94 | race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace)); | |
95 | race->hitcount = 0; | |
96 | race->addr = addr; | |
97 | race->size = size; | |
98 | race->file = f; | |
99 | race->line = l; | |
100 | race->desc[0] = 0; | |
101 | if (desc) { | |
102 | int i = 0; | |
103 | for (; i < kMaxDescLen - 1 && desc[i]; i++) | |
104 | race->desc[i] = desc[i]; | |
105 | race->desc[i] = 0; | |
106 | } | |
107 | race->prev = list; | |
108 | race->next = list->next; | |
109 | race->next->prev = race; | |
110 | list->next = race; | |
111 | } | |
112 | ||
113 | static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) { | |
114 | for (ExpectRace *race = list->next; race != list; race = race->next) { | |
115 | uptr maxbegin = max(race->addr, addr); | |
116 | uptr minend = min(race->addr + race->size, addr + size); | |
117 | if (maxbegin < minend) | |
118 | return race; | |
119 | } | |
120 | return 0; | |
121 | } | |
122 | ||
123 | static bool CheckContains(ExpectRace *list, uptr addr, uptr size) { | |
124 | ExpectRace *race = FindRace(list, addr, size); | |
125 | if (race == 0 && AlternativeAddress(addr)) | |
126 | race = FindRace(list, AlternativeAddress(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 | ||
135 | static void InitList(ExpectRace *list) { | |
136 | list->next = list; | |
137 | list->prev = list; | |
138 | } | |
139 | ||
140 | void 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 | ||
146 | bool 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 | ||
155 | } // namespace __tsan | |
156 | ||
157 | using namespace __tsan; // NOLINT | |
158 | ||
159 | extern "C" { | |
cd0be65c WM |
160 | void AnnotateHappensBefore(char *f, int l, uptr addr) { |
161 | SCOPED_ANNOTATION(AnnotateHappensBefore); | |
162 | Release(cur_thread(), CALLERPC, addr); | |
163 | } | |
164 | ||
cd0be65c WM |
165 | void AnnotateHappensAfter(char *f, int l, uptr addr) { |
166 | SCOPED_ANNOTATION(AnnotateHappensAfter); | |
167 | Acquire(cur_thread(), CALLERPC, addr); | |
168 | } | |
169 | ||
cd0be65c WM |
170 | void AnnotateCondVarSignal(char *f, int l, uptr cv) { |
171 | SCOPED_ANNOTATION(AnnotateCondVarSignal); | |
172 | } | |
173 | ||
cd0be65c WM |
174 | void AnnotateCondVarSignalAll(char *f, int l, uptr cv) { |
175 | SCOPED_ANNOTATION(AnnotateCondVarSignalAll); | |
176 | } | |
177 | ||
cd0be65c WM |
178 | void AnnotateMutexIsNotPHB(char *f, int l, uptr mu) { |
179 | SCOPED_ANNOTATION(AnnotateMutexIsNotPHB); | |
180 | } | |
181 | ||
cd0be65c WM |
182 | void AnnotateCondVarWait(char *f, int l, uptr cv, uptr lock) { |
183 | SCOPED_ANNOTATION(AnnotateCondVarWait); | |
184 | } | |
185 | ||
cd0be65c WM |
186 | void AnnotateRWLockCreate(char *f, int l, uptr m) { |
187 | SCOPED_ANNOTATION(AnnotateRWLockCreate); | |
188 | MutexCreate(thr, pc, m, true, true, false); | |
189 | } | |
190 | ||
cd0be65c WM |
191 | void AnnotateRWLockCreateStatic(char *f, int l, uptr m) { |
192 | SCOPED_ANNOTATION(AnnotateRWLockCreateStatic); | |
193 | MutexCreate(thr, pc, m, true, true, true); | |
194 | } | |
195 | ||
cd0be65c WM |
196 | void AnnotateRWLockDestroy(char *f, int l, uptr m) { |
197 | SCOPED_ANNOTATION(AnnotateRWLockDestroy); | |
198 | MutexDestroy(thr, pc, m); | |
199 | } | |
200 | ||
cd0be65c WM |
201 | void AnnotateRWLockAcquired(char *f, int l, uptr m, uptr is_w) { |
202 | SCOPED_ANNOTATION(AnnotateRWLockAcquired); | |
203 | if (is_w) | |
204 | MutexLock(thr, pc, m); | |
205 | else | |
206 | MutexReadLock(thr, pc, m); | |
207 | } | |
208 | ||
cd0be65c WM |
209 | void AnnotateRWLockReleased(char *f, int l, uptr m, uptr is_w) { |
210 | SCOPED_ANNOTATION(AnnotateRWLockReleased); | |
211 | if (is_w) | |
212 | MutexUnlock(thr, pc, m); | |
213 | else | |
214 | MutexReadUnlock(thr, pc, m); | |
215 | } | |
216 | ||
cd0be65c WM |
217 | void AnnotateTraceMemory(char *f, int l, uptr mem) { |
218 | SCOPED_ANNOTATION(AnnotateTraceMemory); | |
219 | } | |
220 | ||
cd0be65c WM |
221 | void AnnotateFlushState(char *f, int l) { |
222 | SCOPED_ANNOTATION(AnnotateFlushState); | |
223 | } | |
224 | ||
cd0be65c WM |
225 | void AnnotateNewMemory(char *f, int l, uptr mem, uptr size) { |
226 | SCOPED_ANNOTATION(AnnotateNewMemory); | |
227 | } | |
228 | ||
cd0be65c WM |
229 | void AnnotateNoOp(char *f, int l, uptr mem) { |
230 | SCOPED_ANNOTATION(AnnotateNoOp); | |
231 | } | |
232 | ||
233 | static void ReportMissedExpectedRace(ExpectRace *race) { | |
e297eb60 KS |
234 | Printf("==================\n"); |
235 | Printf("WARNING: ThreadSanitizer: missed expected data race\n"); | |
236 | Printf(" %s addr=%zx %s:%d\n", | |
cd0be65c | 237 | race->desc, race->addr, race->file, race->line); |
e297eb60 | 238 | Printf("==================\n"); |
cd0be65c WM |
239 | } |
240 | ||
cd0be65c WM |
241 | void AnnotateFlushExpectedRaces(char *f, int l) { |
242 | SCOPED_ANNOTATION(AnnotateFlushExpectedRaces); | |
243 | Lock lock(&dyn_ann_ctx->mtx); | |
244 | while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) { | |
245 | ExpectRace *race = dyn_ann_ctx->expect.next; | |
246 | if (race->hitcount == 0) { | |
247 | CTX()->nmissed_expected++; | |
248 | ReportMissedExpectedRace(race); | |
249 | } | |
250 | race->prev->next = race->next; | |
251 | race->next->prev = race->prev; | |
252 | internal_free(race); | |
253 | } | |
254 | } | |
255 | ||
cd0be65c WM |
256 | void AnnotateEnableRaceDetection(char *f, int l, int enable) { |
257 | SCOPED_ANNOTATION(AnnotateEnableRaceDetection); | |
258 | // FIXME: Reconsider this functionality later. It may be irrelevant. | |
259 | } | |
260 | ||
cd0be65c WM |
261 | void AnnotateMutexIsUsedAsCondVar(char *f, int l, uptr mu) { |
262 | SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar); | |
263 | } | |
264 | ||
cd0be65c WM |
265 | void AnnotatePCQGet(char *f, int l, uptr pcq) { |
266 | SCOPED_ANNOTATION(AnnotatePCQGet); | |
267 | } | |
268 | ||
cd0be65c WM |
269 | void AnnotatePCQPut(char *f, int l, uptr pcq) { |
270 | SCOPED_ANNOTATION(AnnotatePCQPut); | |
271 | } | |
272 | ||
cd0be65c WM |
273 | void AnnotatePCQDestroy(char *f, int l, uptr pcq) { |
274 | SCOPED_ANNOTATION(AnnotatePCQDestroy); | |
275 | } | |
276 | ||
cd0be65c WM |
277 | void AnnotatePCQCreate(char *f, int l, uptr pcq) { |
278 | SCOPED_ANNOTATION(AnnotatePCQCreate); | |
279 | } | |
280 | ||
cd0be65c WM |
281 | void AnnotateExpectRace(char *f, int l, uptr mem, char *desc) { |
282 | SCOPED_ANNOTATION(AnnotateExpectRace); | |
283 | Lock lock(&dyn_ann_ctx->mtx); | |
284 | AddExpectRace(&dyn_ann_ctx->expect, | |
285 | f, l, mem, 1, desc); | |
286 | DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l); | |
287 | } | |
288 | ||
289 | static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) { | |
290 | Lock lock(&dyn_ann_ctx->mtx); | |
291 | AddExpectRace(&dyn_ann_ctx->benign, | |
292 | f, l, mem, size, desc); | |
293 | DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l); | |
294 | } | |
295 | ||
296 | // FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm. | |
cd0be65c WM |
297 | void AnnotateBenignRaceSized(char *f, int l, uptr mem, uptr size, char *desc) { |
298 | SCOPED_ANNOTATION(AnnotateBenignRaceSized); | |
299 | BenignRaceImpl(f, l, mem, size, desc); | |
300 | } | |
301 | ||
cd0be65c WM |
302 | void AnnotateBenignRace(char *f, int l, uptr mem, char *desc) { |
303 | SCOPED_ANNOTATION(AnnotateBenignRace); | |
304 | BenignRaceImpl(f, l, mem, 1, desc); | |
305 | } | |
306 | ||
cd0be65c WM |
307 | void AnnotateIgnoreReadsBegin(char *f, int l) { |
308 | SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin); | |
309 | IgnoreCtl(cur_thread(), false, true); | |
310 | } | |
311 | ||
cd0be65c WM |
312 | void AnnotateIgnoreReadsEnd(char *f, int l) { |
313 | SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd); | |
314 | IgnoreCtl(cur_thread(), false, false); | |
315 | } | |
316 | ||
cd0be65c WM |
317 | void AnnotateIgnoreWritesBegin(char *f, int l) { |
318 | SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin); | |
319 | IgnoreCtl(cur_thread(), true, true); | |
320 | } | |
321 | ||
cd0be65c WM |
322 | void AnnotateIgnoreWritesEnd(char *f, int l) { |
323 | SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd); | |
324 | IgnoreCtl(cur_thread(), true, false); | |
325 | } | |
326 | ||
cd0be65c WM |
327 | void AnnotatePublishMemoryRange(char *f, int l, uptr addr, uptr size) { |
328 | SCOPED_ANNOTATION(AnnotatePublishMemoryRange); | |
329 | } | |
330 | ||
cd0be65c WM |
331 | void AnnotateUnpublishMemoryRange(char *f, int l, uptr addr, uptr size) { |
332 | SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange); | |
333 | } | |
334 | ||
cd0be65c WM |
335 | void AnnotateThreadName(char *f, int l, char *name) { |
336 | SCOPED_ANNOTATION(AnnotateThreadName); | |
337 | } | |
338 | ||
cd0be65c WM |
339 | void WTFAnnotateHappensBefore(char *f, int l, uptr addr) { |
340 | SCOPED_ANNOTATION(AnnotateHappensBefore); | |
341 | } | |
342 | ||
cd0be65c WM |
343 | void WTFAnnotateHappensAfter(char *f, int l, uptr addr) { |
344 | SCOPED_ANNOTATION(AnnotateHappensAfter); | |
345 | } | |
346 | ||
cd0be65c WM |
347 | void WTFAnnotateBenignRaceSized(char *f, int l, uptr mem, uptr sz, char *desc) { |
348 | SCOPED_ANNOTATION(AnnotateBenignRaceSized); | |
349 | } | |
350 | ||
cd0be65c WM |
351 | int RunningOnValgrind() { |
352 | return flags()->running_on_valgrind; | |
353 | } | |
354 | ||
355 | double __attribute__((weak)) ValgrindSlowdown(void) { | |
356 | return 10.0; | |
357 | } | |
358 | ||
cd0be65c WM |
359 | const char *ThreadSanitizerQuery(const char *query) { |
360 | if (internal_strcmp(query, "pure_happens_before") == 0) | |
361 | return "1"; | |
362 | else | |
363 | return "0"; | |
364 | } | |
365 | } // extern "C" |