1 #include "dfsan_thread.h" 2 3 #include <pthread.h> 4 5 #include "dfsan.h" 6 #include "sanitizer_common/sanitizer_tls_get_addr.h" 7 8 namespace __dfsan { 9 10 DFsanThread *DFsanThread::Create(void *start_routine_trampoline, 11 thread_callback_t start_routine, void *arg, 12 bool track_origins) { 13 uptr PageSize = GetPageSizeCached(); 14 uptr size = RoundUpTo(sizeof(DFsanThread), PageSize); 15 DFsanThread *thread = (DFsanThread *)MmapOrDie(size, __func__); 16 thread->start_routine_trampoline_ = start_routine_trampoline; 17 thread->start_routine_ = start_routine; 18 thread->arg_ = arg; 19 thread->track_origins_ = track_origins; 20 thread->destructor_iterations_ = GetPthreadDestructorIterations(); 21 22 return thread; 23 } 24 25 void DFsanThread::SetThreadStackAndTls() { 26 uptr tls_size = 0; 27 uptr stack_size = 0; 28 GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_, 29 &tls_size); 30 stack_.top = stack_.bottom + stack_size; 31 tls_end_ = tls_begin_ + tls_size; 32 33 int local; 34 CHECK(AddrIsInStack((uptr)&local)); 35 } 36 37 void DFsanThread::ClearShadowForThreadStackAndTLS() { 38 dfsan_set_label(0, (void *)stack_.bottom, stack_.top - stack_.bottom); 39 if (tls_begin_ != tls_end_) 40 dfsan_set_label(0, (void *)tls_begin_, tls_end_ - tls_begin_); 41 DTLS *dtls = DTLS_Get(); 42 CHECK_NE(dtls, 0); 43 ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) { 44 dfsan_set_label(0, (void *)(dtv.beg), dtv.size); 45 }); 46 } 47 48 void DFsanThread::Init() { 49 SetThreadStackAndTls(); 50 ClearShadowForThreadStackAndTLS(); 51 } 52 53 void DFsanThread::TSDDtor(void *tsd) { 54 DFsanThread *t = (DFsanThread *)tsd; 55 t->Destroy(); 56 } 57 58 void DFsanThread::Destroy() { 59 malloc_storage().CommitBack(); 60 // We also clear the shadow on thread destruction because 61 // some code may still be executing in later TSD destructors 62 // and we don't want it to have any poisoned stack. 63 ClearShadowForThreadStackAndTLS(); 64 uptr size = RoundUpTo(sizeof(DFsanThread), GetPageSizeCached()); 65 UnmapOrDie(this, size); 66 DTLS_Destroy(); 67 } 68 69 thread_return_t DFsanThread::ThreadStart() { 70 Init(); 71 72 if (!start_routine_) { 73 // start_routine_ == 0 if we're on the main thread or on one of the 74 // OS X libdispatch worker threads. But nobody is supposed to call 75 // ThreadStart() for the worker threads. 76 return 0; 77 } 78 79 CHECK(start_routine_trampoline_); 80 81 typedef void *(*thread_callback_trampoline_t)(void *, void *, dfsan_label, 82 dfsan_label *); 83 typedef void *(*thread_callback_origin_trampoline_t)( 84 void *, void *, dfsan_label, dfsan_label *, dfsan_origin, dfsan_origin *); 85 86 dfsan_label ret_label; 87 if (!track_origins_) 88 return ((thread_callback_trampoline_t) 89 start_routine_trampoline_)((void *)start_routine_, arg_, 0, 90 &ret_label); 91 92 dfsan_origin ret_origin; 93 return ((thread_callback_origin_trampoline_t) 94 start_routine_trampoline_)((void *)start_routine_, arg_, 0, 95 &ret_label, 0, &ret_origin); 96 } 97 98 DFsanThread::StackBounds DFsanThread::GetStackBounds() const { 99 return {stack_.bottom, stack_.top}; 100 } 101 102 uptr DFsanThread::stack_top() { return GetStackBounds().top; } 103 104 uptr DFsanThread::stack_bottom() { return GetStackBounds().bottom; } 105 106 bool DFsanThread::AddrIsInStack(uptr addr) { 107 const auto bounds = GetStackBounds(); 108 return addr >= bounds.bottom && addr < bounds.top; 109 } 110 111 static pthread_key_t tsd_key; 112 static bool tsd_key_inited = false; 113 114 void DFsanTSDInit(void (*destructor)(void *tsd)) { 115 CHECK(!tsd_key_inited); 116 tsd_key_inited = true; 117 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 118 } 119 120 static THREADLOCAL DFsanThread *dfsan_current_thread; 121 122 DFsanThread *GetCurrentThread() { return dfsan_current_thread; } 123 124 void SetCurrentThread(DFsanThread *t) { 125 // Make sure we do not reset the current DFsanThread. 126 CHECK_EQ(0, dfsan_current_thread); 127 dfsan_current_thread = t; 128 // Make sure that DFsanTSDDtor gets called at the end. 129 CHECK(tsd_key_inited); 130 pthread_setspecific(tsd_key, t); 131 } 132 133 void DFsanTSDDtor(void *tsd) { 134 DFsanThread *t = (DFsanThread *)tsd; 135 if (t->destructor_iterations_ > 1) { 136 t->destructor_iterations_--; 137 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 138 return; 139 } 140 dfsan_current_thread = nullptr; 141 // Make sure that signal handler can not see a stale current thread pointer. 142 atomic_signal_fence(memory_order_seq_cst); 143 DFsanThread::TSDDtor(tsd); 144 } 145 146 } // namespace __dfsan 147