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