blob: 9298bf051af2cbc67b62187b53201cf8dcdc5cd1 [file] [log] [blame]
Dmitry Vyukovfce5bd42012-06-29 16:58:33 +00001
Alexey Samsonov603c4be2012-06-04 13:55:19 +00002//===-- tsan_test_util_linux.cc -------------------------------------------===//
Kostya Serebryanyda4edd82012-05-10 14:18:22 +00003//
4// The LLVM Compiler Infrastructure
5//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10//
11// This file is a part of ThreadSanitizer (TSan), a race detector.
12//
Stephen Hines6d186232014-11-26 17:56:19 -080013// Test utils, Linux and FreeBSD implementation.
Kostya Serebryanyda4edd82012-05-10 14:18:22 +000014//===----------------------------------------------------------------------===//
15
Dmitry Vyukovfce5bd42012-06-29 16:58:33 +000016#include "sanitizer_common/sanitizer_atomic.h"
Kostya Serebryanyda4edd82012-05-10 14:18:22 +000017#include "tsan_interface.h"
18#include "tsan_test_util.h"
Kostya Serebryanyda4edd82012-05-10 14:18:22 +000019#include "tsan_report.h"
20
21#include "gtest/gtest.h"
22
23#include <assert.h>
24#include <pthread.h>
25#include <stdio.h>
26#include <stdint.h>
27#include <string.h>
28#include <unistd.h>
29#include <errno.h>
30
31using namespace __tsan; // NOLINT
32
33static __thread bool expect_report;
34static __thread bool expect_report_reported;
35static __thread ReportType expect_report_type;
36
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +000037extern "C" void *__interceptor_memcpy(void*, const void*, uptr);
38extern "C" void *__interceptor_memset(void*, int, uptr);
39
Kostya Serebryanyda4edd82012-05-10 14:18:22 +000040static void *BeforeInitThread(void *param) {
41 (void)param;
42 return 0;
43}
44
45static void AtExit() {
46}
47
48void TestMutexBeforeInit() {
49 // Mutexes must be usable before __tsan_init();
50 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
51 pthread_mutex_lock(&mtx);
52 pthread_mutex_unlock(&mtx);
53 pthread_mutex_destroy(&mtx);
54 pthread_t thr;
55 pthread_create(&thr, 0, BeforeInitThread, 0);
56 pthread_join(thr, 0);
57 atexit(AtExit);
58}
59
60namespace __tsan {
61bool OnReport(const ReportDesc *rep, bool suppressed) {
62 if (expect_report) {
63 if (rep->typ != expect_report_type) {
64 printf("Expected report of type %d, got type %d\n",
65 (int)expect_report_type, (int)rep->typ);
66 EXPECT_FALSE("Wrong report type");
67 return false;
68 }
69 } else {
70 EXPECT_FALSE("Unexpected report");
71 return false;
72 }
73 expect_report_reported = true;
74 return true;
75}
Alexey Samsonovba5e9962013-01-30 07:45:58 +000076} // namespace __tsan
Kostya Serebryanyda4edd82012-05-10 14:18:22 +000077
78static void* allocate_addr(int size, int offset_from_aligned = 0) {
79 static uintptr_t foo;
80 static atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address.
81 const int kAlign = 16;
82 CHECK(offset_from_aligned < kAlign);
83 size = (size + 2 * kAlign) & ~(kAlign - 1);
84 uintptr_t addr = atomic_fetch_add(&uniq, size, memory_order_relaxed);
85 return (void*)(addr + offset_from_aligned);
86}
87
88MemLoc::MemLoc(int offset_from_aligned)
89 : loc_(allocate_addr(16, offset_from_aligned)) {
90}
91
92MemLoc::~MemLoc() {
93}
94
95Mutex::Mutex(Type type)
96 : alive_()
97 , type_(type) {
98}
99
100Mutex::~Mutex() {
101 CHECK(!alive_);
102}
103
104void Mutex::Init() {
105 CHECK(!alive_);
106 alive_ = true;
107 if (type_ == Normal)
108 CHECK_EQ(pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
109 else if (type_ == Spin)
110 CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
111 else if (type_ == RW)
112 CHECK_EQ(pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
113 else
114 CHECK(0);
115}
116
117void Mutex::StaticInit() {
118 CHECK(!alive_);
119 CHECK(type_ == Normal);
120 alive_ = true;
121 pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
122 memcpy(mtx_, &tmp, sizeof(tmp));
123}
124
125void Mutex::Destroy() {
126 CHECK(alive_);
127 alive_ = false;
128 if (type_ == Normal)
129 CHECK_EQ(pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
130 else if (type_ == Spin)
131 CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
132 else if (type_ == RW)
133 CHECK_EQ(pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
134}
135
136void Mutex::Lock() {
137 CHECK(alive_);
138 if (type_ == Normal)
139 CHECK_EQ(pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
140 else if (type_ == Spin)
141 CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
142 else if (type_ == RW)
143 CHECK_EQ(pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
144}
145
146bool Mutex::TryLock() {
147 CHECK(alive_);
148 if (type_ == Normal)
149 return pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
150 else if (type_ == Spin)
151 return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
152 else if (type_ == RW)
153 return pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
154 return false;
155}
156
157void Mutex::Unlock() {
158 CHECK(alive_);
159 if (type_ == Normal)
160 CHECK_EQ(pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
161 else if (type_ == Spin)
162 CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
163 else if (type_ == RW)
164 CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
165}
166
167void Mutex::ReadLock() {
168 CHECK(alive_);
169 CHECK(type_ == RW);
170 CHECK_EQ(pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0);
171}
172
173bool Mutex::TryReadLock() {
174 CHECK(alive_);
175 CHECK(type_ == RW);
176 return pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0;
177}
178
179void Mutex::ReadUnlock() {
180 CHECK(alive_);
181 CHECK(type_ == RW);
182 CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
183}
184
185struct Event {
186 enum Type {
187 SHUTDOWN,
188 READ,
189 WRITE,
190 VPTR_UPDATE,
191 CALL,
192 RETURN,
193 MUTEX_CREATE,
194 MUTEX_DESTROY,
195 MUTEX_LOCK,
196 MUTEX_TRYLOCK,
197 MUTEX_UNLOCK,
198 MUTEX_READLOCK,
199 MUTEX_TRYREADLOCK,
200 MUTEX_READUNLOCK,
201 MEMCPY,
202 MEMSET
203 };
204 Type type;
205 void *ptr;
206 uptr arg;
207 uptr arg2;
208 bool res;
209 bool expect_report;
210 ReportType report_type;
211
212 Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0)
213 : type(type)
214 , ptr(const_cast<void*>(ptr))
215 , arg(arg)
216 , arg2(arg2)
217 , res()
218 , expect_report()
219 , report_type() {
220 }
221
222 void ExpectReport(ReportType type) {
223 expect_report = true;
224 report_type = type;
225 }
226};
227
228struct ScopedThread::Impl {
229 pthread_t thread;
230 bool main;
231 bool detached;
232 atomic_uintptr_t event; // Event*
233
234 static void *ScopedThreadCallback(void *arg);
235 void send(Event *ev);
236 void HandleEvent(Event *ev);
237};
238
239void ScopedThread::Impl::HandleEvent(Event *ev) {
240 CHECK_EQ(expect_report, false);
241 expect_report = ev->expect_report;
242 expect_report_reported = false;
243 expect_report_type = ev->report_type;
244 switch (ev->type) {
245 case Event::READ:
246 case Event::WRITE: {
247 void (*tsan_mop)(void *addr) = 0;
248 if (ev->type == Event::READ) {
249 switch (ev->arg /*size*/) {
250 case 1: tsan_mop = __tsan_read1; break;
251 case 2: tsan_mop = __tsan_read2; break;
252 case 4: tsan_mop = __tsan_read4; break;
253 case 8: tsan_mop = __tsan_read8; break;
254 case 16: tsan_mop = __tsan_read16; break;
255 }
256 } else {
257 switch (ev->arg /*size*/) {
258 case 1: tsan_mop = __tsan_write1; break;
259 case 2: tsan_mop = __tsan_write2; break;
260 case 4: tsan_mop = __tsan_write4; break;
261 case 8: tsan_mop = __tsan_write8; break;
262 case 16: tsan_mop = __tsan_write16; break;
263 }
264 }
265 CHECK_NE(tsan_mop, 0);
Stephen Hines6d186232014-11-26 17:56:19 -0800266#if defined(__FreeBSD__)
267 const int ErrCode = ESOCKTNOSUPPORT;
268#else
269 const int ErrCode = ECHRNG;
270#endif
271 errno = ErrCode;
Kostya Serebryanyda4edd82012-05-10 14:18:22 +0000272 tsan_mop(ev->ptr);
Stephen Hines6d186232014-11-26 17:56:19 -0800273 CHECK_EQ(ErrCode, errno); // In no case must errno be changed.
Kostya Serebryanyda4edd82012-05-10 14:18:22 +0000274 break;
275 }
276 case Event::VPTR_UPDATE:
277 __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg);
278 break;
279 case Event::CALL:
280 __tsan_func_entry((void*)((uptr)ev->ptr));
281 break;
282 case Event::RETURN:
283 __tsan_func_exit();
284 break;
285 case Event::MUTEX_CREATE:
286 static_cast<Mutex*>(ev->ptr)->Init();
287 break;
288 case Event::MUTEX_DESTROY:
289 static_cast<Mutex*>(ev->ptr)->Destroy();
290 break;
291 case Event::MUTEX_LOCK:
292 static_cast<Mutex*>(ev->ptr)->Lock();
293 break;
294 case Event::MUTEX_TRYLOCK:
295 ev->res = static_cast<Mutex*>(ev->ptr)->TryLock();
296 break;
297 case Event::MUTEX_UNLOCK:
298 static_cast<Mutex*>(ev->ptr)->Unlock();
299 break;
300 case Event::MUTEX_READLOCK:
301 static_cast<Mutex*>(ev->ptr)->ReadLock();
302 break;
303 case Event::MUTEX_TRYREADLOCK:
304 ev->res = static_cast<Mutex*>(ev->ptr)->TryReadLock();
305 break;
306 case Event::MUTEX_READUNLOCK:
307 static_cast<Mutex*>(ev->ptr)->ReadUnlock();
308 break;
309 case Event::MEMCPY:
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +0000310 __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2);
Kostya Serebryanyda4edd82012-05-10 14:18:22 +0000311 break;
312 case Event::MEMSET:
Dmitry Vyukovd51a1a12012-06-27 21:00:23 +0000313 __interceptor_memset(ev->ptr, ev->arg, ev->arg2);
Kostya Serebryanyda4edd82012-05-10 14:18:22 +0000314 break;
315 default: CHECK(0);
316 }
317 if (expect_report && !expect_report_reported) {
318 printf("Missed expected report of type %d\n", (int)ev->report_type);
319 EXPECT_FALSE("Missed expected race");
320 }
321 expect_report = false;
322}
323
324void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
325 __tsan_func_entry(__builtin_return_address(0));
326 Impl *impl = (Impl*)arg;
327 for (;;) {
328 Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire);
329 if (ev == 0) {
330 pthread_yield();
331 continue;
332 }
333 if (ev->type == Event::SHUTDOWN) {
334 atomic_store(&impl->event, 0, memory_order_release);
335 break;
336 }
337 impl->HandleEvent(ev);
338 atomic_store(&impl->event, 0, memory_order_release);
339 }
340 __tsan_func_exit();
341 return 0;
342}
343
344void ScopedThread::Impl::send(Event *e) {
345 if (main) {
346 HandleEvent(e);
347 } else {
348 CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0);
349 atomic_store(&event, (uintptr_t)e, memory_order_release);
350 while (atomic_load(&event, memory_order_acquire) != 0)
351 pthread_yield();
352 }
353}
354
355ScopedThread::ScopedThread(bool detached, bool main) {
356 impl_ = new Impl;
357 impl_->main = main;
358 impl_->detached = detached;
359 atomic_store(&impl_->event, 0, memory_order_relaxed);
360 if (!main) {
361 pthread_attr_t attr;
362 pthread_attr_init(&attr);
363 pthread_attr_setdetachstate(&attr, detached);
Dmitry Vyukov9d2ffc22012-05-22 14:34:43 +0000364 pthread_attr_setstacksize(&attr, 64*1024);
Kostya Serebryanyda4edd82012-05-10 14:18:22 +0000365 pthread_create(&impl_->thread, &attr,
366 ScopedThread::Impl::ScopedThreadCallback, impl_);
367 }
368}
369
370ScopedThread::~ScopedThread() {
371 if (!impl_->main) {
372 Event event(Event::SHUTDOWN);
373 impl_->send(&event);
374 if (!impl_->detached)
375 pthread_join(impl_->thread, 0);
376 }
377 delete impl_;
378}
379
380void ScopedThread::Detach() {
381 CHECK(!impl_->main);
382 CHECK(!impl_->detached);
383 impl_->detached = true;
384 pthread_detach(impl_->thread);
385}
386
387void ScopedThread::Access(void *addr, bool is_write,
388 int size, bool expect_race) {
389 Event event(is_write ? Event::WRITE : Event::READ, addr, size);
390 if (expect_race)
391 event.ExpectReport(ReportTypeRace);
392 impl_->send(&event);
393}
394
395void ScopedThread::VptrUpdate(const MemLoc &vptr,
396 const MemLoc &new_val,
397 bool expect_race) {
398 Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc());
399 if (expect_race)
400 event.ExpectReport(ReportTypeRace);
401 impl_->send(&event);
402}
403
404void ScopedThread::Call(void(*pc)()) {
Alexey Samsonove64c3b62012-09-18 08:33:37 +0000405 Event event(Event::CALL, (void*)((uintptr_t)pc));
Kostya Serebryanyda4edd82012-05-10 14:18:22 +0000406 impl_->send(&event);
407}
408
409void ScopedThread::Return() {
410 Event event(Event::RETURN);
411 impl_->send(&event);
412}
413
414void ScopedThread::Create(const Mutex &m) {
415 Event event(Event::MUTEX_CREATE, &m);
416 impl_->send(&event);
417}
418
419void ScopedThread::Destroy(const Mutex &m) {
420 Event event(Event::MUTEX_DESTROY, &m);
421 impl_->send(&event);
422}
423
424void ScopedThread::Lock(const Mutex &m) {
425 Event event(Event::MUTEX_LOCK, &m);
426 impl_->send(&event);
427}
428
429bool ScopedThread::TryLock(const Mutex &m) {
430 Event event(Event::MUTEX_TRYLOCK, &m);
431 impl_->send(&event);
432 return event.res;
433}
434
435void ScopedThread::Unlock(const Mutex &m) {
436 Event event(Event::MUTEX_UNLOCK, &m);
437 impl_->send(&event);
438}
439
440void ScopedThread::ReadLock(const Mutex &m) {
441 Event event(Event::MUTEX_READLOCK, &m);
442 impl_->send(&event);
443}
444
445bool ScopedThread::TryReadLock(const Mutex &m) {
446 Event event(Event::MUTEX_TRYREADLOCK, &m);
447 impl_->send(&event);
448 return event.res;
449}
450
451void ScopedThread::ReadUnlock(const Mutex &m) {
452 Event event(Event::MUTEX_READUNLOCK, &m);
453 impl_->send(&event);
454}
455
456void ScopedThread::Memcpy(void *dst, const void *src, int size,
457 bool expect_race) {
458 Event event(Event::MEMCPY, dst, (uptr)src, size);
459 if (expect_race)
460 event.ExpectReport(ReportTypeRace);
461 impl_->send(&event);
462}
463
464void ScopedThread::Memset(void *dst, int val, int size,
465 bool expect_race) {
466 Event event(Event::MEMSET, dst, val, size);
467 if (expect_race)
468 event.ExpectReport(ReportTypeRace);
469 impl_->send(&event);
470}