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