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 if (!start_routine_) { 71 // start_routine_ == 0 if we're on the main thread or on one of the 72 // OS X libdispatch worker threads. But nobody is supposed to call 73 // ThreadStart() for the worker threads. 74 return 0; 75 } 76 77 CHECK(start_routine_trampoline_); 78 79 typedef void *(*thread_callback_trampoline_t)(void *, void *, dfsan_label, 80 dfsan_label *); 81 typedef void *(*thread_callback_origin_trampoline_t)( 82 void *, void *, dfsan_label, dfsan_label *, dfsan_origin, dfsan_origin *); 83 84 dfsan_label ret_label; 85 if (!track_origins_) 86 return ((thread_callback_trampoline_t) 87 start_routine_trampoline_)((void *)start_routine_, arg_, 0, 88 &ret_label); 89 90 dfsan_origin ret_origin; 91 return ((thread_callback_origin_trampoline_t) 92 start_routine_trampoline_)((void *)start_routine_, arg_, 0, 93 &ret_label, 0, &ret_origin); 94 } 95 96 DFsanThread::StackBounds DFsanThread::GetStackBounds() const { 97 return {stack_.bottom, stack_.top}; 98 } 99 100 uptr DFsanThread::stack_top() { return GetStackBounds().top; } 101 102 uptr DFsanThread::stack_bottom() { return GetStackBounds().bottom; } 103 104 bool DFsanThread::AddrIsInStack(uptr addr) { 105 const auto bounds = GetStackBounds(); 106 return addr >= bounds.bottom && addr < bounds.top; 107 } 108 109 static pthread_key_t tsd_key; 110 static bool tsd_key_inited = false; 111 112 void DFsanTSDInit(void (*destructor)(void *tsd)) { 113 CHECK(!tsd_key_inited); 114 tsd_key_inited = true; 115 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 116 } 117 118 static THREADLOCAL DFsanThread *dfsan_current_thread; 119 120 DFsanThread *GetCurrentThread() { return dfsan_current_thread; } 121 122 void SetCurrentThread(DFsanThread *t) { 123 // Make sure we do not reset the current DFsanThread. 124 CHECK_EQ(0, dfsan_current_thread); 125 dfsan_current_thread = t; 126 // Make sure that DFsanTSDDtor gets called at the end. 127 CHECK(tsd_key_inited); 128 pthread_setspecific(tsd_key, t); 129 } 130 131 void DFsanTSDDtor(void *tsd) { 132 DFsanThread *t = (DFsanThread *)tsd; 133 if (t->destructor_iterations_ > 1) { 134 t->destructor_iterations_--; 135 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 136 return; 137 } 138 dfsan_current_thread = nullptr; 139 // Make sure that signal handler can not see a stale current thread pointer. 140 atomic_signal_fence(memory_order_seq_cst); 141 DFsanThread::TSDDtor(tsd); 142 } 143 144 } // namespace __dfsan 145