1 2 //===-- tsan_test_util_linux.cc -------------------------------------------===// 3 // 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 // 13 // Test utils, linux implementation. 14 //===----------------------------------------------------------------------===// 15 16 #include "sanitizer_common/sanitizer_atomic.h" 17 #include "tsan_interface.h" 18 #include "tsan_test_util.h" 19 #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 31 using namespace __tsan; // NOLINT 32 33 static __thread bool expect_report; 34 static __thread bool expect_report_reported; 35 static __thread ReportType expect_report_type; 36 37 extern "C" void *__interceptor_memcpy(void*, const void*, uptr); 38 extern "C" void *__interceptor_memset(void*, int, uptr); 39 40 static void *BeforeInitThread(void *param) { 41 (void)param; 42 return 0; 43 } 44 45 static void AtExit() { 46 } 47 48 void 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 60 namespace __tsan { 61 bool 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 } 76 } // namespace __tsan 77 78 static 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 88 MemLoc::MemLoc(int offset_from_aligned) 89 : loc_(allocate_addr(16, offset_from_aligned)) { 90 } 91 92 MemLoc::~MemLoc() { 93 } 94 95 Mutex::Mutex(Type type) 96 : alive_() 97 , type_(type) { 98 } 99 100 Mutex::~Mutex() { 101 CHECK(!alive_); 102 } 103 104 void 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 117 void 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 125 void 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 136 void 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 146 bool 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 157 void 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 167 void Mutex::ReadLock() { 168 CHECK(alive_); 169 CHECK(type_ == RW); 170 CHECK_EQ(pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0); 171 } 172 173 bool Mutex::TryReadLock() { 174 CHECK(alive_); 175 CHECK(type_ == RW); 176 return pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0; 177 } 178 179 void Mutex::ReadUnlock() { 180 CHECK(alive_); 181 CHECK(type_ == RW); 182 CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0); 183 } 184 185 struct 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 228 struct 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 239 void 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); 266 errno = ECHRNG; 267 tsan_mop(ev->ptr); 268 CHECK_EQ(errno, ECHRNG); // In no case must errno be changed. 269 break; 270 } 271 case Event::VPTR_UPDATE: 272 __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg); 273 break; 274 case Event::CALL: 275 __tsan_func_entry((void*)((uptr)ev->ptr)); 276 break; 277 case Event::RETURN: 278 __tsan_func_exit(); 279 break; 280 case Event::MUTEX_CREATE: 281 static_cast<Mutex*>(ev->ptr)->Init(); 282 break; 283 case Event::MUTEX_DESTROY: 284 static_cast<Mutex*>(ev->ptr)->Destroy(); 285 break; 286 case Event::MUTEX_LOCK: 287 static_cast<Mutex*>(ev->ptr)->Lock(); 288 break; 289 case Event::MUTEX_TRYLOCK: 290 ev->res = static_cast<Mutex*>(ev->ptr)->TryLock(); 291 break; 292 case Event::MUTEX_UNLOCK: 293 static_cast<Mutex*>(ev->ptr)->Unlock(); 294 break; 295 case Event::MUTEX_READLOCK: 296 static_cast<Mutex*>(ev->ptr)->ReadLock(); 297 break; 298 case Event::MUTEX_TRYREADLOCK: 299 ev->res = static_cast<Mutex*>(ev->ptr)->TryReadLock(); 300 break; 301 case Event::MUTEX_READUNLOCK: 302 static_cast<Mutex*>(ev->ptr)->ReadUnlock(); 303 break; 304 case Event::MEMCPY: 305 __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2); 306 break; 307 case Event::MEMSET: 308 __interceptor_memset(ev->ptr, ev->arg, ev->arg2); 309 break; 310 default: CHECK(0); 311 } 312 if (expect_report && !expect_report_reported) { 313 printf("Missed expected report of type %d\n", (int)ev->report_type); 314 EXPECT_FALSE("Missed expected race"); 315 } 316 expect_report = false; 317 } 318 319 void *ScopedThread::Impl::ScopedThreadCallback(void *arg) { 320 __tsan_func_entry(__builtin_return_address(0)); 321 Impl *impl = (Impl*)arg; 322 for (;;) { 323 Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire); 324 if (ev == 0) { 325 pthread_yield(); 326 continue; 327 } 328 if (ev->type == Event::SHUTDOWN) { 329 atomic_store(&impl->event, 0, memory_order_release); 330 break; 331 } 332 impl->HandleEvent(ev); 333 atomic_store(&impl->event, 0, memory_order_release); 334 } 335 __tsan_func_exit(); 336 return 0; 337 } 338 339 void ScopedThread::Impl::send(Event *e) { 340 if (main) { 341 HandleEvent(e); 342 } else { 343 CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0); 344 atomic_store(&event, (uintptr_t)e, memory_order_release); 345 while (atomic_load(&event, memory_order_acquire) != 0) 346 pthread_yield(); 347 } 348 } 349 350 ScopedThread::ScopedThread(bool detached, bool main) { 351 impl_ = new Impl; 352 impl_->main = main; 353 impl_->detached = detached; 354 atomic_store(&impl_->event, 0, memory_order_relaxed); 355 if (!main) { 356 pthread_attr_t attr; 357 pthread_attr_init(&attr); 358 pthread_attr_setdetachstate(&attr, detached); 359 pthread_attr_setstacksize(&attr, 64*1024); 360 pthread_create(&impl_->thread, &attr, 361 ScopedThread::Impl::ScopedThreadCallback, impl_); 362 } 363 } 364 365 ScopedThread::~ScopedThread() { 366 if (!impl_->main) { 367 Event event(Event::SHUTDOWN); 368 impl_->send(&event); 369 if (!impl_->detached) 370 pthread_join(impl_->thread, 0); 371 } 372 delete impl_; 373 } 374 375 void ScopedThread::Detach() { 376 CHECK(!impl_->main); 377 CHECK(!impl_->detached); 378 impl_->detached = true; 379 pthread_detach(impl_->thread); 380 } 381 382 void ScopedThread::Access(void *addr, bool is_write, 383 int size, bool expect_race) { 384 Event event(is_write ? Event::WRITE : Event::READ, addr, size); 385 if (expect_race) 386 event.ExpectReport(ReportTypeRace); 387 impl_->send(&event); 388 } 389 390 void ScopedThread::VptrUpdate(const MemLoc &vptr, 391 const MemLoc &new_val, 392 bool expect_race) { 393 Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc()); 394 if (expect_race) 395 event.ExpectReport(ReportTypeRace); 396 impl_->send(&event); 397 } 398 399 void ScopedThread::Call(void(*pc)()) { 400 Event event(Event::CALL, (void*)((uintptr_t)pc)); 401 impl_->send(&event); 402 } 403 404 void ScopedThread::Return() { 405 Event event(Event::RETURN); 406 impl_->send(&event); 407 } 408 409 void ScopedThread::Create(const Mutex &m) { 410 Event event(Event::MUTEX_CREATE, &m); 411 impl_->send(&event); 412 } 413 414 void ScopedThread::Destroy(const Mutex &m) { 415 Event event(Event::MUTEX_DESTROY, &m); 416 impl_->send(&event); 417 } 418 419 void ScopedThread::Lock(const Mutex &m) { 420 Event event(Event::MUTEX_LOCK, &m); 421 impl_->send(&event); 422 } 423 424 bool ScopedThread::TryLock(const Mutex &m) { 425 Event event(Event::MUTEX_TRYLOCK, &m); 426 impl_->send(&event); 427 return event.res; 428 } 429 430 void ScopedThread::Unlock(const Mutex &m) { 431 Event event(Event::MUTEX_UNLOCK, &m); 432 impl_->send(&event); 433 } 434 435 void ScopedThread::ReadLock(const Mutex &m) { 436 Event event(Event::MUTEX_READLOCK, &m); 437 impl_->send(&event); 438 } 439 440 bool ScopedThread::TryReadLock(const Mutex &m) { 441 Event event(Event::MUTEX_TRYREADLOCK, &m); 442 impl_->send(&event); 443 return event.res; 444 } 445 446 void ScopedThread::ReadUnlock(const Mutex &m) { 447 Event event(Event::MUTEX_READUNLOCK, &m); 448 impl_->send(&event); 449 } 450 451 void ScopedThread::Memcpy(void *dst, const void *src, int size, 452 bool expect_race) { 453 Event event(Event::MEMCPY, dst, (uptr)src, size); 454 if (expect_race) 455 event.ExpectReport(ReportTypeRace); 456 impl_->send(&event); 457 } 458 459 void ScopedThread::Memset(void *dst, int val, int size, 460 bool expect_race) { 461 Event event(Event::MEMSET, dst, val, size); 462 if (expect_race) 463 event.ExpectReport(ReportTypeRace); 464 impl_->send(&event); 465 } 466