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 | namespace __msan { |
9 | |
10 | MsanThread *MsanThread::Create(thread_callback_t start_routine, |
11 | void *arg) { |
12 | uptr PageSize = GetPageSizeCached(); |
13 | uptr size = RoundUpTo(size: sizeof(MsanThread), boundary: PageSize); |
14 | MsanThread *thread = (MsanThread*)MmapOrDie(size, mem_type: __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(main: IsMainThread(), stk_addr: &stack_.bottom, stk_size: &stack_size, tls_addr: &tls_begin_, |
26 | tls_size: &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(a: (void *)stack_.bottom, size: stack_.top - stack_.bottom); |
36 | if (tls_begin_ != tls_end_) |
37 | __msan_unpoison(a: (void *)tls_begin_, size: tls_end_ - tls_begin_); |
38 | DTLS *dtls = DTLS_Get(); |
39 | CHECK_NE(dtls, 0); |
40 | ForEachDVT(dtls, fn: [](const DTLS::DTV &dtv, int id) { |
41 | __msan_unpoison(a: (void *)(dtv.beg), size: 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 | malloc_storage().Init(); |
51 | } |
52 | |
53 | void MsanThread::TSDDtor(void *tsd) { |
54 | MsanThread *t = (MsanThread*)tsd; |
55 | t->Destroy(); |
56 | } |
57 | |
58 | void MsanThread::Destroy() { |
59 | malloc_storage().CommitBack(); |
60 | // We also clear the shadow on thread destruction because |
61 | // some code may still be executing in later TSD destructors |
62 | // and we don't want it to have any poisoned stack. |
63 | ClearShadowForThreadStackAndTLS(); |
64 | uptr size = RoundUpTo(size: sizeof(MsanThread), boundary: GetPageSizeCached()); |
65 | UnmapOrDie(addr: this, size); |
66 | DTLS_Destroy(); |
67 | } |
68 | |
69 | thread_return_t MsanThread::ThreadStart() { |
70 | if (!start_routine_) { |
71 | // start_routine_ == 0 if we're on the main thread or on one of the |
72 | // OS X libdispatch worker threads. But nobody is supposed to call |
73 | // ThreadStart() for the worker threads. |
74 | return 0; |
75 | } |
76 | |
77 | thread_return_t res = start_routine_(arg_); |
78 | |
79 | return res; |
80 | } |
81 | |
82 | MsanThread::StackBounds MsanThread::GetStackBounds() const { |
83 | if (!stack_switching_) |
84 | return {.bottom: stack_.bottom, .top: stack_.top}; |
85 | const uptr cur_stack = GET_CURRENT_FRAME(); |
86 | // Note: need to check next stack first, because FinishSwitchFiber |
87 | // may be in process of overwriting stack_.top/bottom_. But in such case |
88 | // we are already on the next stack. |
89 | if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top) |
90 | return {.bottom: next_stack_.bottom, .top: next_stack_.top}; |
91 | return {.bottom: stack_.bottom, .top: stack_.top}; |
92 | } |
93 | |
94 | uptr MsanThread::stack_top() { return GetStackBounds().top; } |
95 | |
96 | uptr MsanThread::stack_bottom() { return GetStackBounds().bottom; } |
97 | |
98 | bool MsanThread::AddrIsInStack(uptr addr) { |
99 | const auto bounds = GetStackBounds(); |
100 | return addr >= bounds.bottom && addr < bounds.top; |
101 | } |
102 | |
103 | void MsanThread::StartSwitchFiber(uptr bottom, uptr size) { |
104 | CHECK(!stack_switching_); |
105 | next_stack_.bottom = bottom; |
106 | next_stack_.top = bottom + size; |
107 | stack_switching_ = true; |
108 | } |
109 | |
110 | void MsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) { |
111 | CHECK(stack_switching_); |
112 | if (bottom_old) |
113 | *bottom_old = stack_.bottom; |
114 | if (size_old) |
115 | *size_old = stack_.top - stack_.bottom; |
116 | stack_.bottom = next_stack_.bottom; |
117 | stack_.top = next_stack_.top; |
118 | stack_switching_ = false; |
119 | next_stack_.top = 0; |
120 | next_stack_.bottom = 0; |
121 | } |
122 | |
123 | } // namespace __msan |
124 | |