115 lines · cpp
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 8using namespace __msan;9 10MsanThread *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 22void MsanThread::SetThreadStackAndTls() {23 GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_.top, &tls_begin_,24 &tls_end_);25 int local;26 CHECK(AddrIsInStack((uptr)&local));27}28 29void 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 40void 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 48void MsanThread::TSDDtor(void *tsd) {49 MsanThread *t = (MsanThread*)tsd;50 t->Destroy();51}52 53void MsanThread::Destroy() {54 malloc_storage().CommitBack();55 // We also clear the shadow on thread destruction because56 // some code may still be executing in later TSD destructors57 // 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 64thread_return_t MsanThread::ThreadStart() {65 if (!start_routine_) {66 // start_routine_ == 0 if we're on the main thread or on one of the67 // OS X libdispatch worker threads. But nobody is supposed to call68 // ThreadStart() for the worker threads.69 return 0;70 }71 72 return start_routine_(arg_);73}74 75MsanThread::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 FinishSwitchFiber80 // may be in process of overwriting stack_.top/bottom_. But in such case81 // 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 87uptr MsanThread::stack_top() { return GetStackBounds().top; }88 89uptr MsanThread::stack_bottom() { return GetStackBounds().bottom; }90 91bool MsanThread::AddrIsInStack(uptr addr) {92 const auto bounds = GetStackBounds();93 return addr >= bounds.bottom && addr < bounds.top;94}95 96void 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 103void 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