168d75effSDimitry Andric 268d75effSDimitry Andric #include "msan.h" 368d75effSDimitry Andric #include "msan_thread.h" 468d75effSDimitry Andric #include "msan_interface_internal.h" 568d75effSDimitry Andric 668d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h" 768d75effSDimitry Andric 868d75effSDimitry Andric namespace __msan { 968d75effSDimitry Andric 1068d75effSDimitry Andric MsanThread *MsanThread::Create(thread_callback_t start_routine, 1168d75effSDimitry Andric void *arg) { 1268d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 1368d75effSDimitry Andric uptr size = RoundUpTo(sizeof(MsanThread), PageSize); 1468d75effSDimitry Andric MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__); 1568d75effSDimitry Andric thread->start_routine_ = start_routine; 1668d75effSDimitry Andric thread->arg_ = arg; 1768d75effSDimitry Andric thread->destructor_iterations_ = GetPthreadDestructorIterations(); 1868d75effSDimitry Andric 1968d75effSDimitry Andric return thread; 2068d75effSDimitry Andric } 2168d75effSDimitry Andric 2268d75effSDimitry Andric void MsanThread::SetThreadStackAndTls() { 2368d75effSDimitry Andric uptr tls_size = 0; 2468d75effSDimitry Andric uptr stack_size = 0; 25*e8d8bef9SDimitry Andric GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_, 26*e8d8bef9SDimitry Andric &tls_size); 27*e8d8bef9SDimitry Andric stack_.top = stack_.bottom + stack_size; 2868d75effSDimitry Andric tls_end_ = tls_begin_ + tls_size; 2968d75effSDimitry Andric 3068d75effSDimitry Andric int local; 3168d75effSDimitry Andric CHECK(AddrIsInStack((uptr)&local)); 3268d75effSDimitry Andric } 3368d75effSDimitry Andric 3468d75effSDimitry Andric void MsanThread::ClearShadowForThreadStackAndTLS() { 35*e8d8bef9SDimitry Andric __msan_unpoison((void *)stack_.bottom, stack_.top - stack_.bottom); 3668d75effSDimitry Andric if (tls_begin_ != tls_end_) 3768d75effSDimitry Andric __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_); 3868d75effSDimitry Andric DTLS *dtls = DTLS_Get(); 3968d75effSDimitry Andric CHECK_NE(dtls, 0); 40*e8d8bef9SDimitry Andric ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) { 41*e8d8bef9SDimitry Andric __msan_unpoison((void *)(dtv.beg), dtv.size); 42*e8d8bef9SDimitry Andric }); 4368d75effSDimitry Andric } 4468d75effSDimitry Andric 4568d75effSDimitry Andric void MsanThread::Init() { 4668d75effSDimitry Andric SetThreadStackAndTls(); 47*e8d8bef9SDimitry Andric CHECK(MEM_IS_APP(stack_.bottom)); 48*e8d8bef9SDimitry Andric CHECK(MEM_IS_APP(stack_.top - 1)); 4968d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 5068d75effSDimitry Andric } 5168d75effSDimitry Andric 5268d75effSDimitry Andric void MsanThread::TSDDtor(void *tsd) { 5368d75effSDimitry Andric MsanThread *t = (MsanThread*)tsd; 5468d75effSDimitry Andric t->Destroy(); 5568d75effSDimitry Andric } 5668d75effSDimitry Andric 5768d75effSDimitry Andric void MsanThread::Destroy() { 5868d75effSDimitry Andric malloc_storage().CommitBack(); 5968d75effSDimitry Andric // We also clear the shadow on thread destruction because 6068d75effSDimitry Andric // some code may still be executing in later TSD destructors 6168d75effSDimitry Andric // and we don't want it to have any poisoned stack. 6268d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 6368d75effSDimitry Andric uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached()); 6468d75effSDimitry Andric UnmapOrDie(this, size); 6568d75effSDimitry Andric DTLS_Destroy(); 6668d75effSDimitry Andric } 6768d75effSDimitry Andric 6868d75effSDimitry Andric thread_return_t MsanThread::ThreadStart() { 6968d75effSDimitry Andric Init(); 7068d75effSDimitry Andric 7168d75effSDimitry Andric if (!start_routine_) { 7268d75effSDimitry Andric // start_routine_ == 0 if we're on the main thread or on one of the 7368d75effSDimitry Andric // OS X libdispatch worker threads. But nobody is supposed to call 7468d75effSDimitry Andric // ThreadStart() for the worker threads. 7568d75effSDimitry Andric return 0; 7668d75effSDimitry Andric } 7768d75effSDimitry Andric 7868d75effSDimitry Andric thread_return_t res = start_routine_(arg_); 7968d75effSDimitry Andric 8068d75effSDimitry Andric return res; 8168d75effSDimitry Andric } 8268d75effSDimitry Andric 83*e8d8bef9SDimitry Andric MsanThread::StackBounds MsanThread::GetStackBounds() const { 84*e8d8bef9SDimitry Andric if (!stack_switching_) 85*e8d8bef9SDimitry Andric return {stack_.bottom, stack_.top}; 86*e8d8bef9SDimitry Andric const uptr cur_stack = GET_CURRENT_FRAME(); 87*e8d8bef9SDimitry Andric // Note: need to check next stack first, because FinishSwitchFiber 88*e8d8bef9SDimitry Andric // may be in process of overwriting stack_.top/bottom_. But in such case 89*e8d8bef9SDimitry Andric // we are already on the next stack. 90*e8d8bef9SDimitry Andric if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top) 91*e8d8bef9SDimitry Andric return {next_stack_.bottom, next_stack_.top}; 92*e8d8bef9SDimitry Andric return {stack_.bottom, stack_.top}; 93*e8d8bef9SDimitry Andric } 94*e8d8bef9SDimitry Andric 95*e8d8bef9SDimitry Andric uptr MsanThread::stack_top() { return GetStackBounds().top; } 96*e8d8bef9SDimitry Andric 97*e8d8bef9SDimitry Andric uptr MsanThread::stack_bottom() { return GetStackBounds().bottom; } 98*e8d8bef9SDimitry Andric 99*e8d8bef9SDimitry Andric bool MsanThread::AddrIsInStack(uptr addr) { 100*e8d8bef9SDimitry Andric const auto bounds = GetStackBounds(); 101*e8d8bef9SDimitry Andric return addr >= bounds.bottom && addr < bounds.top; 102*e8d8bef9SDimitry Andric } 103*e8d8bef9SDimitry Andric 104*e8d8bef9SDimitry Andric void MsanThread::StartSwitchFiber(uptr bottom, uptr size) { 105*e8d8bef9SDimitry Andric CHECK(!stack_switching_); 106*e8d8bef9SDimitry Andric next_stack_.bottom = bottom; 107*e8d8bef9SDimitry Andric next_stack_.top = bottom + size; 108*e8d8bef9SDimitry Andric stack_switching_ = true; 109*e8d8bef9SDimitry Andric } 110*e8d8bef9SDimitry Andric 111*e8d8bef9SDimitry Andric void MsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) { 112*e8d8bef9SDimitry Andric CHECK(stack_switching_); 113*e8d8bef9SDimitry Andric if (bottom_old) 114*e8d8bef9SDimitry Andric *bottom_old = stack_.bottom; 115*e8d8bef9SDimitry Andric if (size_old) 116*e8d8bef9SDimitry Andric *size_old = stack_.top - stack_.bottom; 117*e8d8bef9SDimitry Andric stack_.bottom = next_stack_.bottom; 118*e8d8bef9SDimitry Andric stack_.top = next_stack_.top; 119*e8d8bef9SDimitry Andric stack_switching_ = false; 120*e8d8bef9SDimitry Andric next_stack_.top = 0; 121*e8d8bef9SDimitry Andric next_stack_.bottom = 0; 122*e8d8bef9SDimitry Andric } 123*e8d8bef9SDimitry Andric 12468d75effSDimitry Andric } // namespace __msan 125