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