1 2 #include "msan.h" 3 #include "msan_thread.h" 4 #include "msan_interface_internal.h" 5 6 #include "sanitizer_common/sanitizer_tls_get_addr.h" 7 8 namespace __msan { 9 10 MsanThread *MsanThread::Create(thread_callback_t start_routine, 11 void *arg) { 12 uptr PageSize = GetPageSizeCached(); 13 uptr size = RoundUpTo(sizeof(MsanThread), PageSize); 14 MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__); 15 thread->start_routine_ = start_routine; 16 thread->arg_ = arg; 17 thread->destructor_iterations_ = GetPthreadDestructorIterations(); 18 19 return thread; 20 } 21 22 void MsanThread::SetThreadStackAndTls() { 23 uptr tls_size = 0; 24 uptr stack_size = 0; 25 GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_, 26 &tls_size); 27 stack_.top = stack_.bottom + stack_size; 28 tls_end_ = tls_begin_ + tls_size; 29 30 int local; 31 CHECK(AddrIsInStack((uptr)&local)); 32 } 33 34 void MsanThread::ClearShadowForThreadStackAndTLS() { 35 __msan_unpoison((void *)stack_.bottom, stack_.top - stack_.bottom); 36 if (tls_begin_ != tls_end_) 37 __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_); 38 DTLS *dtls = DTLS_Get(); 39 CHECK_NE(dtls, 0); 40 ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) { 41 __msan_unpoison((void *)(dtv.beg), dtv.size); 42 }); 43 } 44 45 void MsanThread::Init() { 46 SetThreadStackAndTls(); 47 CHECK(MEM_IS_APP(stack_.bottom)); 48 CHECK(MEM_IS_APP(stack_.top - 1)); 49 ClearShadowForThreadStackAndTLS(); 50 } 51 52 void MsanThread::TSDDtor(void *tsd) { 53 MsanThread *t = (MsanThread*)tsd; 54 t->Destroy(); 55 } 56 57 void MsanThread::Destroy() { 58 malloc_storage().CommitBack(); 59 // We also clear the shadow on thread destruction because 60 // some code may still be executing in later TSD destructors 61 // and we don't want it to have any poisoned stack. 62 ClearShadowForThreadStackAndTLS(); 63 uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached()); 64 UnmapOrDie(this, size); 65 DTLS_Destroy(); 66 } 67 68 thread_return_t MsanThread::ThreadStart() { 69 Init(); 70 71 if (!start_routine_) { 72 // start_routine_ == 0 if we're on the main thread or on one of the 73 // OS X libdispatch worker threads. But nobody is supposed to call 74 // ThreadStart() for the worker threads. 75 return 0; 76 } 77 78 thread_return_t res = start_routine_(arg_); 79 80 return res; 81 } 82 83 MsanThread::StackBounds MsanThread::GetStackBounds() const { 84 if (!stack_switching_) 85 return {stack_.bottom, stack_.top}; 86 const uptr cur_stack = GET_CURRENT_FRAME(); 87 // Note: need to check next stack first, because FinishSwitchFiber 88 // may be in process of overwriting stack_.top/bottom_. But in such case 89 // we are already on the next stack. 90 if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top) 91 return {next_stack_.bottom, next_stack_.top}; 92 return {stack_.bottom, stack_.top}; 93 } 94 95 uptr MsanThread::stack_top() { return GetStackBounds().top; } 96 97 uptr MsanThread::stack_bottom() { return GetStackBounds().bottom; } 98 99 bool MsanThread::AddrIsInStack(uptr addr) { 100 const auto bounds = GetStackBounds(); 101 return addr >= bounds.bottom && addr < bounds.top; 102 } 103 104 void MsanThread::StartSwitchFiber(uptr bottom, uptr size) { 105 CHECK(!stack_switching_); 106 next_stack_.bottom = bottom; 107 next_stack_.top = bottom + size; 108 stack_switching_ = true; 109 } 110 111 void MsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) { 112 CHECK(stack_switching_); 113 if (bottom_old) 114 *bottom_old = stack_.bottom; 115 if (size_old) 116 *size_old = stack_.top - stack_.bottom; 117 stack_.bottom = next_stack_.bottom; 118 stack_.top = next_stack_.top; 119 stack_switching_ = false; 120 next_stack_.top = 0; 121 next_stack_.bottom = 0; 122 } 123 124 } // namespace __msan 125