1//===-- tsan_test_util_posix.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// Test utils, Linux, FreeBSD, NetBSD and Darwin implementation. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_common/sanitizer_atomic.h" 15#include "tsan_interface.h" 16#include "tsan_posix_util.h" 17#include "tsan_rtl.h" 18#include "tsan_test_util.h" 19#include "tsan_report.h" 20 21#include <assert.h> 22#include <pthread.h> 23#include <stdio.h> 24#include <stdint.h> 25#include <string.h> 26#include <unistd.h> 27#include <errno.h> 28 29#define CALLERPC (__builtin_return_address(0)) 30 31static __thread bool expect_report; 32static __thread bool expect_report_reported; 33static __thread __tsan::ReportType expect_report_type; 34 35void ThreadSanitizer::TearDown() { 36 __tsan::ctx->racy_stacks.Reset(); 37} 38 39static void *BeforeInitThread(void *param) { 40 (void)param; 41 return 0; 42} 43 44static void AtExit() { 45} 46 47void TestMutexBeforeInit() { 48 // Mutexes must be usable before __tsan_init(); 49 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 50 __interceptor_pthread_mutex_lock(&mtx); 51 __interceptor_pthread_mutex_unlock(&mtx); 52 __interceptor_pthread_mutex_destroy(&mtx); 53 pthread_t thr; 54 __interceptor_pthread_create(&thr, 0, BeforeInitThread, 0); 55 __interceptor_pthread_join(thr, 0); 56 atexit(AtExit); 57} 58 59namespace __tsan { 60bool OnReport(const ReportDesc *rep, bool suppressed) { 61 if (expect_report) { 62 if (rep->typ != expect_report_type) { 63 printf("Expected report of type %d, got type %d\n", 64 (int)expect_report_type, (int)rep->typ); 65 EXPECT_TRUE(false) << "Wrong report type"; 66 return false; 67 } 68 } else { 69 EXPECT_TRUE(false) << "Unexpected report"; 70 return false; 71 } 72 expect_report_reported = true; 73 return true; 74} 75} // namespace __tsan 76 77static void* allocate_addr(int size, int offset_from_aligned = 0) { 78 static uintptr_t foo; 79 static __tsan::atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address. 80 const int kAlign = 16; 81 CHECK(offset_from_aligned < kAlign); 82 size = (size + 2 * kAlign) & ~(kAlign - 1); 83 uintptr_t addr = atomic_fetch_add(&uniq, size, __tsan::memory_order_relaxed); 84 return (void*)(addr + offset_from_aligned); 85} 86 87MemLoc::MemLoc(int offset_from_aligned) 88 : loc_(allocate_addr(16, offset_from_aligned)) { 89} 90 91MemLoc::~MemLoc() { 92} 93 94UserMutex::UserMutex(Type type) : alive_(), type_(type) {} 95 96UserMutex::~UserMutex() { CHECK(!alive_); } 97 98void UserMutex::Init() { 99 CHECK(!alive_); 100 alive_ = true; 101 if (type_ == Normal) 102 CHECK_EQ(__interceptor_pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0); 103#ifndef __APPLE__ 104 else if (type_ == Spin) 105 CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0); 106#endif 107 else if (type_ == RW) 108 CHECK_EQ(__interceptor_pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0); 109 else 110 CHECK(0); 111} 112 113void UserMutex::StaticInit() { 114 CHECK(!alive_); 115 CHECK(type_ == Normal); 116 alive_ = true; 117 pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER; 118 memcpy(mtx_, &tmp, sizeof(tmp)); 119} 120 121void UserMutex::Destroy() { 122 CHECK(alive_); 123 alive_ = false; 124 if (type_ == Normal) 125 CHECK_EQ(__interceptor_pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0); 126#ifndef __APPLE__ 127 else if (type_ == Spin) 128 CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0); 129#endif 130 else if (type_ == RW) 131 CHECK_EQ(__interceptor_pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0); 132} 133 134void UserMutex::Lock() { 135 CHECK(alive_); 136 if (type_ == Normal) 137 CHECK_EQ(__interceptor_pthread_mutex_lock((pthread_mutex_t*)mtx_), 0); 138#ifndef __APPLE__ 139 else if (type_ == Spin) 140 CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0); 141#endif 142 else if (type_ == RW) 143 CHECK_EQ(__interceptor_pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0); 144} 145 146bool UserMutex::TryLock() { 147 CHECK(alive_); 148 if (type_ == Normal) 149 return __interceptor_pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0; 150#ifndef __APPLE__ 151 else if (type_ == Spin) 152 return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0; 153#endif 154 else if (type_ == RW) 155 return __interceptor_pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0; 156 return false; 157} 158 159void UserMutex::Unlock() { 160 CHECK(alive_); 161 if (type_ == Normal) 162 CHECK_EQ(__interceptor_pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0); 163#ifndef __APPLE__ 164 else if (type_ == Spin) 165 CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0); 166#endif 167 else if (type_ == RW) 168 CHECK_EQ(__interceptor_pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0); 169} 170 171void UserMutex::ReadLock() { 172 CHECK(alive_); 173 CHECK(type_ == RW); 174 CHECK_EQ(__interceptor_pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0); 175} 176 177bool UserMutex::TryReadLock() { 178 CHECK(alive_); 179 CHECK(type_ == RW); 180 return __interceptor_pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) == 0; 181} 182 183void UserMutex::ReadUnlock() { 184 CHECK(alive_); 185 CHECK(type_ == RW); 186 CHECK_EQ(__interceptor_pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0); 187} 188 189struct Event { 190 enum Type { 191 SHUTDOWN, 192 READ, 193 WRITE, 194 VPTR_UPDATE, 195 CALL, 196 RETURN, 197 MUTEX_CREATE, 198 MUTEX_DESTROY, 199 MUTEX_LOCK, 200 MUTEX_TRYLOCK, 201 MUTEX_UNLOCK, 202 MUTEX_READLOCK, 203 MUTEX_TRYREADLOCK, 204 MUTEX_READUNLOCK, 205 MEMCPY, 206 MEMSET 207 }; 208 Type type; 209 void *ptr; 210 uptr arg; 211 uptr arg2; 212 bool res; 213 bool expect_report; 214 __tsan::ReportType report_type; 215 216 explicit Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0) 217 : type(type), 218 ptr(const_cast<void *>(ptr)), 219 arg(arg), 220 arg2(arg2), 221 res(), 222 expect_report(), 223 report_type() {} 224 225 void ExpectReport(__tsan::ReportType type) { 226 expect_report = true; 227 report_type = type; 228 } 229}; 230 231struct ScopedThread::Impl { 232 pthread_t thread; 233 bool main; 234 bool detached; 235 __tsan::atomic_uintptr_t event; // Event* 236 237 static void *ScopedThreadCallback(void *arg); 238 void send(Event *ev); 239 void HandleEvent(Event *ev); 240}; 241 242void ScopedThread::Impl::HandleEvent(Event *ev) { 243 CHECK_EQ(expect_report, false); 244 expect_report = ev->expect_report; 245 expect_report_reported = false; 246 expect_report_type = ev->report_type; 247 switch (ev->type) { 248 case Event::READ: 249 case Event::WRITE: { 250 void (*tsan_mop)(void *addr, void *pc) = 0; 251 if (ev->type == Event::READ) { 252 switch (ev->arg /*size*/) { 253 case 1: 254 tsan_mop = __tsan_read1_pc; 255 break; 256 case 2: 257 tsan_mop = __tsan_read2_pc; 258 break; 259 case 4: 260 tsan_mop = __tsan_read4_pc; 261 break; 262 case 8: 263 tsan_mop = __tsan_read8_pc; 264 break; 265 case 16: 266 tsan_mop = __tsan_read16_pc; 267 break; 268 } 269 } else { 270 switch (ev->arg /*size*/) { 271 case 1: 272 tsan_mop = __tsan_write1_pc; 273 break; 274 case 2: 275 tsan_mop = __tsan_write2_pc; 276 break; 277 case 4: 278 tsan_mop = __tsan_write4_pc; 279 break; 280 case 8: 281 tsan_mop = __tsan_write8_pc; 282 break; 283 case 16: 284 tsan_mop = __tsan_write16_pc; 285 break; 286 } 287 } 288 CHECK_NE(tsan_mop, 0); 289#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) 290 const int ErrCode = ESOCKTNOSUPPORT; 291#else 292 const int ErrCode = ECHRNG; 293#endif 294 errno = ErrCode; 295 tsan_mop(ev->ptr, (void *)ev->arg2); 296 CHECK_EQ(ErrCode, errno); // In no case must errno be changed. 297 break; 298 } 299 case Event::VPTR_UPDATE: 300 __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg); 301 break; 302 case Event::CALL: 303 __tsan_func_entry((void*)((uptr)ev->ptr)); 304 break; 305 case Event::RETURN: 306 __tsan_func_exit(); 307 break; 308 case Event::MUTEX_CREATE: 309 static_cast<UserMutex *>(ev->ptr)->Init(); 310 break; 311 case Event::MUTEX_DESTROY: 312 static_cast<UserMutex *>(ev->ptr)->Destroy(); 313 break; 314 case Event::MUTEX_LOCK: 315 static_cast<UserMutex *>(ev->ptr)->Lock(); 316 break; 317 case Event::MUTEX_TRYLOCK: 318 ev->res = static_cast<UserMutex *>(ev->ptr)->TryLock(); 319 break; 320 case Event::MUTEX_UNLOCK: 321 static_cast<UserMutex *>(ev->ptr)->Unlock(); 322 break; 323 case Event::MUTEX_READLOCK: 324 static_cast<UserMutex *>(ev->ptr)->ReadLock(); 325 break; 326 case Event::MUTEX_TRYREADLOCK: 327 ev->res = static_cast<UserMutex *>(ev->ptr)->TryReadLock(); 328 break; 329 case Event::MUTEX_READUNLOCK: 330 static_cast<UserMutex *>(ev->ptr)->ReadUnlock(); 331 break; 332 case Event::MEMCPY: 333 __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2); 334 break; 335 case Event::MEMSET: 336 __interceptor_memset(ev->ptr, ev->arg, ev->arg2); 337 break; 338 default: CHECK(0); 339 } 340 if (expect_report && !expect_report_reported) { 341 printf("Missed expected report of type %d\n", (int)ev->report_type); 342 EXPECT_TRUE(false) << "Missed expected race"; 343 } 344 expect_report = false; 345} 346 347void *ScopedThread::Impl::ScopedThreadCallback(void *arg) { 348 __tsan_func_entry(CALLERPC); 349 Impl *impl = (Impl*)arg; 350 for (;;) { 351 Event *ev = 352 (Event *)atomic_load(&impl->event, __tsan::memory_order_acquire); 353 if (ev == 0) { 354 sched_yield(); 355 continue; 356 } 357 if (ev->type == Event::SHUTDOWN) { 358 atomic_store(&impl->event, 0, __tsan::memory_order_release); 359 break; 360 } 361 impl->HandleEvent(ev); 362 atomic_store(&impl->event, 0, __tsan::memory_order_release); 363 } 364 __tsan_func_exit(); 365 return 0; 366} 367 368void ScopedThread::Impl::send(Event *e) { 369 if (main) { 370 HandleEvent(e); 371 } else { 372 CHECK_EQ(atomic_load(&event, __tsan::memory_order_relaxed), 0); 373 atomic_store(&event, (uintptr_t)e, __tsan::memory_order_release); 374 while (atomic_load(&event, __tsan::memory_order_acquire) != 0) 375 sched_yield(); 376 } 377} 378 379ScopedThread::ScopedThread(bool detached, bool main) { 380 impl_ = new Impl; 381 impl_->main = main; 382 impl_->detached = detached; 383 atomic_store(&impl_->event, 0, __tsan::memory_order_relaxed); 384 if (!main) { 385 pthread_attr_t attr; 386 pthread_attr_init(&attr); 387 pthread_attr_setdetachstate( 388 &attr, detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE); 389 pthread_attr_setstacksize(&attr, 64*1024); 390 __interceptor_pthread_create(&impl_->thread, &attr, 391 ScopedThread::Impl::ScopedThreadCallback, impl_); 392 } 393} 394 395ScopedThread::~ScopedThread() { 396 if (!impl_->main) { 397 Event event(Event::SHUTDOWN); 398 impl_->send(&event); 399 if (!impl_->detached) 400 __interceptor_pthread_join(impl_->thread, 0); 401 } 402 delete impl_; 403} 404 405void ScopedThread::Detach() { 406 CHECK(!impl_->main); 407 CHECK(!impl_->detached); 408 impl_->detached = true; 409 __interceptor_pthread_detach(impl_->thread); 410} 411 412void ScopedThread::Access(void *addr, bool is_write, 413 int size, bool expect_race) { 414 Event event(is_write ? Event::WRITE : Event::READ, addr, size, 415 (uptr)CALLERPC); 416 if (expect_race) 417 event.ExpectReport(__tsan::ReportTypeRace); 418 impl_->send(&event); 419} 420 421void ScopedThread::VptrUpdate(const MemLoc &vptr, 422 const MemLoc &new_val, 423 bool expect_race) { 424 Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc()); 425 if (expect_race) 426 event.ExpectReport(__tsan::ReportTypeRace); 427 impl_->send(&event); 428} 429 430void ScopedThread::Call(void(*pc)()) { 431 Event event(Event::CALL, (void*)((uintptr_t)pc)); 432 impl_->send(&event); 433} 434 435void ScopedThread::Return() { 436 Event event(Event::RETURN); 437 impl_->send(&event); 438} 439 440void ScopedThread::Create(const UserMutex &m) { 441 Event event(Event::MUTEX_CREATE, &m); 442 impl_->send(&event); 443} 444 445void ScopedThread::Destroy(const UserMutex &m) { 446 Event event(Event::MUTEX_DESTROY, &m); 447 impl_->send(&event); 448} 449 450void ScopedThread::Lock(const UserMutex &m) { 451 Event event(Event::MUTEX_LOCK, &m); 452 impl_->send(&event); 453} 454 455bool ScopedThread::TryLock(const UserMutex &m) { 456 Event event(Event::MUTEX_TRYLOCK, &m); 457 impl_->send(&event); 458 return event.res; 459} 460 461void ScopedThread::Unlock(const UserMutex &m) { 462 Event event(Event::MUTEX_UNLOCK, &m); 463 impl_->send(&event); 464} 465 466void ScopedThread::ReadLock(const UserMutex &m) { 467 Event event(Event::MUTEX_READLOCK, &m); 468 impl_->send(&event); 469} 470 471bool ScopedThread::TryReadLock(const UserMutex &m) { 472 Event event(Event::MUTEX_TRYREADLOCK, &m); 473 impl_->send(&event); 474 return event.res; 475} 476 477void ScopedThread::ReadUnlock(const UserMutex &m) { 478 Event event(Event::MUTEX_READUNLOCK, &m); 479 impl_->send(&event); 480} 481 482void ScopedThread::Memcpy(void *dst, const void *src, int size, 483 bool expect_race) { 484 Event event(Event::MEMCPY, dst, (uptr)src, size); 485 if (expect_race) 486 event.ExpectReport(__tsan::ReportTypeRace); 487 impl_->send(&event); 488} 489 490void ScopedThread::Memset(void *dst, int val, int size, 491 bool expect_race) { 492 Event event(Event::MEMSET, dst, val, size); 493 if (expect_race) 494 event.ExpectReport(__tsan::ReportTypeRace); 495 impl_->send(&event); 496} 497