1 #include "dfsan_thread.h"
2
3 #include <pthread.h>
4
5 #include "dfsan.h"
6 #include "sanitizer_common/sanitizer_tls_get_addr.h"
7
8 namespace __dfsan {
9
Create(void * start_routine_trampoline,thread_callback_t start_routine,void * arg,bool track_origins)10 DFsanThread *DFsanThread::Create(void *start_routine_trampoline,
11 thread_callback_t start_routine, void *arg,
12 bool track_origins) {
13 uptr PageSize = GetPageSizeCached();
14 uptr size = RoundUpTo(sizeof(DFsanThread), PageSize);
15 DFsanThread *thread = (DFsanThread *)MmapOrDie(size, __func__);
16 thread->start_routine_trampoline_ = start_routine_trampoline;
17 thread->start_routine_ = start_routine;
18 thread->arg_ = arg;
19 thread->track_origins_ = track_origins;
20 thread->destructor_iterations_ = GetPthreadDestructorIterations();
21
22 return thread;
23 }
24
SetThreadStackAndTls()25 void DFsanThread::SetThreadStackAndTls() {
26 uptr tls_size = 0;
27 uptr stack_size = 0;
28 GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_,
29 &tls_size);
30 stack_.top = stack_.bottom + stack_size;
31 tls_end_ = tls_begin_ + tls_size;
32
33 int local;
34 CHECK(AddrIsInStack((uptr)&local));
35 }
36
ClearShadowForThreadStackAndTLS()37 void DFsanThread::ClearShadowForThreadStackAndTLS() {
38 dfsan_set_label(0, (void *)stack_.bottom, stack_.top - stack_.bottom);
39 if (tls_begin_ != tls_end_)
40 dfsan_set_label(0, (void *)tls_begin_, tls_end_ - tls_begin_);
41 DTLS *dtls = DTLS_Get();
42 CHECK_NE(dtls, 0);
43 ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) {
44 dfsan_set_label(0, (void *)(dtv.beg), dtv.size);
45 });
46 }
47
Init()48 void DFsanThread::Init() {
49 SetThreadStackAndTls();
50 ClearShadowForThreadStackAndTLS();
51 }
52
TSDDtor(void * tsd)53 void DFsanThread::TSDDtor(void *tsd) {
54 DFsanThread *t = (DFsanThread *)tsd;
55 t->Destroy();
56 }
57
Destroy()58 void DFsanThread::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(sizeof(DFsanThread), GetPageSizeCached());
65 UnmapOrDie(this, size);
66 DTLS_Destroy();
67 }
68
ThreadStart()69 thread_return_t DFsanThread::ThreadStart() {
70 Init();
71
72 if (!start_routine_) {
73 // start_routine_ == 0 if we're on the main thread or on one of the
74 // OS X libdispatch worker threads. But nobody is supposed to call
75 // ThreadStart() for the worker threads.
76 return 0;
77 }
78
79 CHECK(start_routine_trampoline_);
80
81 typedef void *(*thread_callback_trampoline_t)(void *, void *, dfsan_label,
82 dfsan_label *);
83 typedef void *(*thread_callback_origin_trampoline_t)(
84 void *, void *, dfsan_label, dfsan_label *, dfsan_origin, dfsan_origin *);
85
86 dfsan_label ret_label;
87 if (!track_origins_)
88 return ((thread_callback_trampoline_t)
89 start_routine_trampoline_)((void *)start_routine_, arg_, 0,
90 &ret_label);
91
92 dfsan_origin ret_origin;
93 return ((thread_callback_origin_trampoline_t)
94 start_routine_trampoline_)((void *)start_routine_, arg_, 0,
95 &ret_label, 0, &ret_origin);
96 }
97
GetStackBounds() const98 DFsanThread::StackBounds DFsanThread::GetStackBounds() const {
99 return {stack_.bottom, stack_.top};
100 }
101
stack_top()102 uptr DFsanThread::stack_top() { return GetStackBounds().top; }
103
stack_bottom()104 uptr DFsanThread::stack_bottom() { return GetStackBounds().bottom; }
105
AddrIsInStack(uptr addr)106 bool DFsanThread::AddrIsInStack(uptr addr) {
107 const auto bounds = GetStackBounds();
108 return addr >= bounds.bottom && addr < bounds.top;
109 }
110
111 static pthread_key_t tsd_key;
112 static bool tsd_key_inited = false;
113
DFsanTSDInit(void (* destructor)(void * tsd))114 void DFsanTSDInit(void (*destructor)(void *tsd)) {
115 CHECK(!tsd_key_inited);
116 tsd_key_inited = true;
117 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
118 }
119
120 static THREADLOCAL DFsanThread *dfsan_current_thread;
121
GetCurrentThread()122 DFsanThread *GetCurrentThread() { return dfsan_current_thread; }
123
SetCurrentThread(DFsanThread * t)124 void SetCurrentThread(DFsanThread *t) {
125 // Make sure we do not reset the current DFsanThread.
126 CHECK_EQ(0, dfsan_current_thread);
127 dfsan_current_thread = t;
128 // Make sure that DFsanTSDDtor gets called at the end.
129 CHECK(tsd_key_inited);
130 pthread_setspecific(tsd_key, t);
131 }
132
DFsanTSDDtor(void * tsd)133 void DFsanTSDDtor(void *tsd) {
134 DFsanThread *t = (DFsanThread *)tsd;
135 if (t->destructor_iterations_ > 1) {
136 t->destructor_iterations_--;
137 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
138 return;
139 }
140 dfsan_current_thread = nullptr;
141 // Make sure that signal handler can not see a stale current thread pointer.
142 atomic_signal_fence(memory_order_seq_cst);
143 DFsanThread::TSDDtor(tsd);
144 }
145
146 } // namespace __dfsan
147