13cab2bb3Spatrick
23cab2bb3Spatrick #include "msan.h"
33cab2bb3Spatrick #include "msan_thread.h"
43cab2bb3Spatrick #include "msan_interface_internal.h"
53cab2bb3Spatrick
63cab2bb3Spatrick #include "sanitizer_common/sanitizer_tls_get_addr.h"
73cab2bb3Spatrick
83cab2bb3Spatrick namespace __msan {
93cab2bb3Spatrick
Create(thread_callback_t start_routine,void * arg)103cab2bb3Spatrick MsanThread *MsanThread::Create(thread_callback_t start_routine,
113cab2bb3Spatrick void *arg) {
123cab2bb3Spatrick uptr PageSize = GetPageSizeCached();
133cab2bb3Spatrick uptr size = RoundUpTo(sizeof(MsanThread), PageSize);
143cab2bb3Spatrick MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__);
153cab2bb3Spatrick thread->start_routine_ = start_routine;
163cab2bb3Spatrick thread->arg_ = arg;
173cab2bb3Spatrick thread->destructor_iterations_ = GetPthreadDestructorIterations();
183cab2bb3Spatrick
193cab2bb3Spatrick return thread;
203cab2bb3Spatrick }
213cab2bb3Spatrick
SetThreadStackAndTls()223cab2bb3Spatrick void MsanThread::SetThreadStackAndTls() {
233cab2bb3Spatrick uptr tls_size = 0;
243cab2bb3Spatrick uptr stack_size = 0;
25*d89ec533Spatrick GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_,
26*d89ec533Spatrick &tls_size);
27*d89ec533Spatrick stack_.top = stack_.bottom + stack_size;
283cab2bb3Spatrick tls_end_ = tls_begin_ + tls_size;
293cab2bb3Spatrick
303cab2bb3Spatrick int local;
313cab2bb3Spatrick CHECK(AddrIsInStack((uptr)&local));
323cab2bb3Spatrick }
333cab2bb3Spatrick
ClearShadowForThreadStackAndTLS()343cab2bb3Spatrick void MsanThread::ClearShadowForThreadStackAndTLS() {
35*d89ec533Spatrick __msan_unpoison((void *)stack_.bottom, stack_.top - stack_.bottom);
363cab2bb3Spatrick if (tls_begin_ != tls_end_)
373cab2bb3Spatrick __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_);
383cab2bb3Spatrick DTLS *dtls = DTLS_Get();
393cab2bb3Spatrick CHECK_NE(dtls, 0);
40*d89ec533Spatrick ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) {
41*d89ec533Spatrick __msan_unpoison((void *)(dtv.beg), dtv.size);
42*d89ec533Spatrick });
433cab2bb3Spatrick }
443cab2bb3Spatrick
Init()453cab2bb3Spatrick void MsanThread::Init() {
463cab2bb3Spatrick SetThreadStackAndTls();
47*d89ec533Spatrick CHECK(MEM_IS_APP(stack_.bottom));
48*d89ec533Spatrick CHECK(MEM_IS_APP(stack_.top - 1));
493cab2bb3Spatrick ClearShadowForThreadStackAndTLS();
503cab2bb3Spatrick }
513cab2bb3Spatrick
TSDDtor(void * tsd)523cab2bb3Spatrick void MsanThread::TSDDtor(void *tsd) {
533cab2bb3Spatrick MsanThread *t = (MsanThread*)tsd;
543cab2bb3Spatrick t->Destroy();
553cab2bb3Spatrick }
563cab2bb3Spatrick
Destroy()573cab2bb3Spatrick void MsanThread::Destroy() {
583cab2bb3Spatrick malloc_storage().CommitBack();
593cab2bb3Spatrick // We also clear the shadow on thread destruction because
603cab2bb3Spatrick // some code may still be executing in later TSD destructors
613cab2bb3Spatrick // and we don't want it to have any poisoned stack.
623cab2bb3Spatrick ClearShadowForThreadStackAndTLS();
633cab2bb3Spatrick uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached());
643cab2bb3Spatrick UnmapOrDie(this, size);
653cab2bb3Spatrick DTLS_Destroy();
663cab2bb3Spatrick }
673cab2bb3Spatrick
ThreadStart()683cab2bb3Spatrick thread_return_t MsanThread::ThreadStart() {
693cab2bb3Spatrick if (!start_routine_) {
703cab2bb3Spatrick // start_routine_ == 0 if we're on the main thread or on one of the
713cab2bb3Spatrick // OS X libdispatch worker threads. But nobody is supposed to call
723cab2bb3Spatrick // ThreadStart() for the worker threads.
733cab2bb3Spatrick return 0;
743cab2bb3Spatrick }
753cab2bb3Spatrick
763cab2bb3Spatrick thread_return_t res = start_routine_(arg_);
773cab2bb3Spatrick
783cab2bb3Spatrick return res;
793cab2bb3Spatrick }
803cab2bb3Spatrick
GetStackBounds() const81*d89ec533Spatrick MsanThread::StackBounds MsanThread::GetStackBounds() const {
82*d89ec533Spatrick if (!stack_switching_)
83*d89ec533Spatrick return {stack_.bottom, stack_.top};
84*d89ec533Spatrick const uptr cur_stack = GET_CURRENT_FRAME();
85*d89ec533Spatrick // Note: need to check next stack first, because FinishSwitchFiber
86*d89ec533Spatrick // may be in process of overwriting stack_.top/bottom_. But in such case
87*d89ec533Spatrick // we are already on the next stack.
88*d89ec533Spatrick if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top)
89*d89ec533Spatrick return {next_stack_.bottom, next_stack_.top};
90*d89ec533Spatrick return {stack_.bottom, stack_.top};
91*d89ec533Spatrick }
92*d89ec533Spatrick
stack_top()93*d89ec533Spatrick uptr MsanThread::stack_top() { return GetStackBounds().top; }
94*d89ec533Spatrick
stack_bottom()95*d89ec533Spatrick uptr MsanThread::stack_bottom() { return GetStackBounds().bottom; }
96*d89ec533Spatrick
AddrIsInStack(uptr addr)97*d89ec533Spatrick bool MsanThread::AddrIsInStack(uptr addr) {
98*d89ec533Spatrick const auto bounds = GetStackBounds();
99*d89ec533Spatrick return addr >= bounds.bottom && addr < bounds.top;
100*d89ec533Spatrick }
101*d89ec533Spatrick
StartSwitchFiber(uptr bottom,uptr size)102*d89ec533Spatrick void MsanThread::StartSwitchFiber(uptr bottom, uptr size) {
103*d89ec533Spatrick CHECK(!stack_switching_);
104*d89ec533Spatrick next_stack_.bottom = bottom;
105*d89ec533Spatrick next_stack_.top = bottom + size;
106*d89ec533Spatrick stack_switching_ = true;
107*d89ec533Spatrick }
108*d89ec533Spatrick
FinishSwitchFiber(uptr * bottom_old,uptr * size_old)109*d89ec533Spatrick void MsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) {
110*d89ec533Spatrick CHECK(stack_switching_);
111*d89ec533Spatrick if (bottom_old)
112*d89ec533Spatrick *bottom_old = stack_.bottom;
113*d89ec533Spatrick if (size_old)
114*d89ec533Spatrick *size_old = stack_.top - stack_.bottom;
115*d89ec533Spatrick stack_.bottom = next_stack_.bottom;
116*d89ec533Spatrick stack_.top = next_stack_.top;
117*d89ec533Spatrick stack_switching_ = false;
118*d89ec533Spatrick next_stack_.top = 0;
119*d89ec533Spatrick next_stack_.bottom = 0;
120*d89ec533Spatrick }
121*d89ec533Spatrick
1223cab2bb3Spatrick } // namespace __msan
123