xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_thread.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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(thread_callback_t start_routine,void * arg,bool track_origins)10 DFsanThread *DFsanThread::Create(thread_callback_t start_routine, void *arg,
11                                  bool track_origins) {
12   uptr PageSize = GetPageSizeCached();
13   uptr size = RoundUpTo(sizeof(DFsanThread), PageSize);
14   DFsanThread *thread = (DFsanThread *)MmapOrDie(size, __func__);
15   thread->start_routine_ = start_routine;
16   thread->arg_ = arg;
17   thread->track_origins_ = track_origins;
18   thread->destructor_iterations_ = GetPthreadDestructorIterations();
19 
20   return thread;
21 }
22 
SetThreadStackAndTls()23 void DFsanThread::SetThreadStackAndTls() {
24   uptr tls_size = 0;
25   uptr stack_size = 0;
26   GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_,
27                        &tls_size);
28   stack_.top = stack_.bottom + stack_size;
29   tls_end_ = tls_begin_ + tls_size;
30 
31   int local;
32   CHECK(AddrIsInStack((uptr)&local));
33 }
34 
ClearShadowForThreadStackAndTLS()35 void DFsanThread::ClearShadowForThreadStackAndTLS() {
36   dfsan_set_label(0, (void *)stack_.bottom, stack_.top - stack_.bottom);
37   if (tls_begin_ != tls_end_)
38     dfsan_set_label(0, (void *)tls_begin_, tls_end_ - tls_begin_);
39   DTLS *dtls = DTLS_Get();
40   CHECK_NE(dtls, 0);
41   ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) {
42     dfsan_set_label(0, (void *)(dtv.beg), dtv.size);
43   });
44 }
45 
Init()46 void DFsanThread::Init() {
47   SetThreadStackAndTls();
48   ClearShadowForThreadStackAndTLS();
49 }
50 
TSDDtor(void * tsd)51 void DFsanThread::TSDDtor(void *tsd) {
52   DFsanThread *t = (DFsanThread *)tsd;
53   t->Destroy();
54 }
55 
Destroy()56 void DFsanThread::Destroy() {
57   malloc_storage().CommitBack();
58   // We also clear the shadow on thread destruction because
59   // some code may still be executing in later TSD destructors
60   // and we don't want it to have any poisoned stack.
61   ClearShadowForThreadStackAndTLS();
62   uptr size = RoundUpTo(sizeof(DFsanThread), GetPageSizeCached());
63   UnmapOrDie(this, size);
64   DTLS_Destroy();
65 }
66 
ThreadStart()67 thread_return_t DFsanThread::ThreadStart() {
68   if (!start_routine_) {
69     // start_routine_ == 0 if we're on the main thread or on one of the
70     // OS X libdispatch worker threads. But nobody is supposed to call
71     // ThreadStart() for the worker threads.
72     return 0;
73   }
74 
75   // The only argument is void* arg.
76   //
77   // We have never supported propagating the pointer arg as tainted,
78   // __dfsw_pthread_create/__dfso_pthread_create ignore the taint label.
79   // Note that the bytes pointed-to (probably the much more common case)
80   // can still have taint labels attached to them.
81   dfsan_clear_thread_local_state();
82 
83   return start_routine_(arg_);
84 }
85 
GetStackBounds() const86 DFsanThread::StackBounds DFsanThread::GetStackBounds() const {
87   return {stack_.bottom, stack_.top};
88 }
89 
stack_top()90 uptr DFsanThread::stack_top() { return GetStackBounds().top; }
91 
stack_bottom()92 uptr DFsanThread::stack_bottom() { return GetStackBounds().bottom; }
93 
AddrIsInStack(uptr addr)94 bool DFsanThread::AddrIsInStack(uptr addr) {
95   const auto bounds = GetStackBounds();
96   return addr >= bounds.bottom && addr < bounds.top;
97 }
98 
99 static pthread_key_t tsd_key;
100 static bool tsd_key_inited = false;
101 
DFsanTSDInit(void (* destructor)(void * tsd))102 void DFsanTSDInit(void (*destructor)(void *tsd)) {
103   CHECK(!tsd_key_inited);
104   tsd_key_inited = true;
105   CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
106 }
107 
108 static THREADLOCAL DFsanThread *dfsan_current_thread;
109 
GetCurrentThread()110 DFsanThread *GetCurrentThread() { return dfsan_current_thread; }
111 
SetCurrentThread(DFsanThread * t)112 void SetCurrentThread(DFsanThread *t) {
113   // Make sure we do not reset the current DFsanThread.
114   CHECK_EQ(0, dfsan_current_thread);
115   dfsan_current_thread = t;
116   // Make sure that DFsanTSDDtor gets called at the end.
117   CHECK(tsd_key_inited);
118   pthread_setspecific(tsd_key, t);
119 }
120 
DFsanTSDDtor(void * tsd)121 void DFsanTSDDtor(void *tsd) {
122   DFsanThread *t = (DFsanThread *)tsd;
123   if (t->destructor_iterations_ > 1) {
124     t->destructor_iterations_--;
125     CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
126     return;
127   }
128   dfsan_current_thread = nullptr;
129   // Make sure that signal handler can not see a stale current thread pointer.
130   atomic_signal_fence(memory_order_seq_cst);
131   DFsanThread::TSDDtor(tsd);
132 }
133 
134 }  // namespace __dfsan
135