1 #include "dfsan_thread.h" 2 3 #include <pthread.h> 4 5 #include "dfsan.h" 6 7 namespace __dfsan { 8 9 DFsanThread *DFsanThread::Create(void *start_routine_trampoline, 10 thread_callback_t start_routine, void *arg) { 11 uptr PageSize = GetPageSizeCached(); 12 uptr size = RoundUpTo(sizeof(DFsanThread), PageSize); 13 DFsanThread *thread = (DFsanThread *)MmapOrDie(size, __func__); 14 thread->start_routine_trampoline_ = start_routine_trampoline; 15 thread->start_routine_ = start_routine; 16 thread->arg_ = arg; 17 thread->destructor_iterations_ = GetPthreadDestructorIterations(); 18 19 return thread; 20 } 21 22 void DFsanThread::SetThreadStackAndTls() { 23 uptr tls_size = 0; 24 uptr stack_size = 0; 25 uptr tls_begin; 26 GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin, 27 &tls_size); 28 stack_.top = stack_.bottom + stack_size; 29 30 int local; 31 CHECK(AddrIsInStack((uptr)&local)); 32 } 33 34 void DFsanThread::Init() { SetThreadStackAndTls(); } 35 36 void DFsanThread::TSDDtor(void *tsd) { 37 DFsanThread *t = (DFsanThread *)tsd; 38 t->Destroy(); 39 } 40 41 void DFsanThread::Destroy() { 42 uptr size = RoundUpTo(sizeof(DFsanThread), GetPageSizeCached()); 43 UnmapOrDie(this, size); 44 } 45 46 thread_return_t DFsanThread::ThreadStart() { 47 Init(); 48 49 if (!start_routine_) { 50 // start_routine_ == 0 if we're on the main thread or on one of the 51 // OS X libdispatch worker threads. But nobody is supposed to call 52 // ThreadStart() for the worker threads. 53 return 0; 54 } 55 56 CHECK(start_routine_trampoline_); 57 58 typedef void *(*thread_callback_trampoline_t)(void *, void *, dfsan_label, 59 dfsan_label *); 60 61 dfsan_label ret_label; 62 return ((thread_callback_trampoline_t) 63 start_routine_trampoline_)((void *)start_routine_, arg_, 0, 64 &ret_label); 65 } 66 67 DFsanThread::StackBounds DFsanThread::GetStackBounds() const { 68 return {stack_.bottom, stack_.top}; 69 } 70 71 uptr DFsanThread::stack_top() { return GetStackBounds().top; } 72 73 uptr DFsanThread::stack_bottom() { return GetStackBounds().bottom; } 74 75 bool DFsanThread::AddrIsInStack(uptr addr) { 76 const auto bounds = GetStackBounds(); 77 return addr >= bounds.bottom && addr < bounds.top; 78 } 79 80 static pthread_key_t tsd_key; 81 static bool tsd_key_inited = false; 82 83 void DFsanTSDInit(void (*destructor)(void *tsd)) { 84 CHECK(!tsd_key_inited); 85 tsd_key_inited = true; 86 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 87 } 88 89 static THREADLOCAL DFsanThread *dfsan_current_thread; 90 91 DFsanThread *GetCurrentThread() { return dfsan_current_thread; } 92 93 void SetCurrentThread(DFsanThread *t) { 94 // Make sure we do not reset the current DFsanThread. 95 CHECK_EQ(0, dfsan_current_thread); 96 dfsan_current_thread = t; 97 // Make sure that DFsanTSDDtor gets called at the end. 98 CHECK(tsd_key_inited); 99 pthread_setspecific(tsd_key, t); 100 } 101 102 void DFsanTSDDtor(void *tsd) { 103 DFsanThread *t = (DFsanThread *)tsd; 104 if (t->destructor_iterations_ > 1) { 105 t->destructor_iterations_--; 106 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 107 return; 108 } 109 dfsan_current_thread = nullptr; 110 // Make sure that signal handler can not see a stale current thread pointer. 111 atomic_signal_fence(memory_order_seq_cst); 112 DFsanThread::TSDDtor(tsd); 113 } 114 115 } // namespace __dfsan 116