Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/nsan/nsan_thread.cpp
213766 views
1
//===- nsan_threads.cpp ---------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
// Thread management.
9
//===----------------------------------------------------------------------===//
10
11
#include "nsan_thread.h"
12
13
#include <pthread.h>
14
15
#include "nsan.h"
16
#include "sanitizer_common/sanitizer_tls_get_addr.h"
17
18
using namespace __nsan;
19
20
NsanThread *NsanThread::Create(thread_callback_t start_routine, void *arg) {
21
uptr PageSize = GetPageSizeCached();
22
uptr size = RoundUpTo(sizeof(NsanThread), PageSize);
23
NsanThread *thread = (NsanThread *)MmapOrDie(size, __func__);
24
thread->start_routine_ = start_routine;
25
thread->arg_ = arg;
26
thread->destructor_iterations_ = GetPthreadDestructorIterations();
27
28
return thread;
29
}
30
31
void NsanThread::SetThreadStackAndTls() {
32
GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_.top, &tls_begin_,
33
&tls_end_);
34
int local;
35
CHECK(AddrIsInStack((uptr)&local));
36
}
37
38
void NsanThread::ClearShadowForThreadStackAndTLS() {
39
__nsan_set_value_unknown((const u8 *)stack_.bottom,
40
stack_.top - stack_.bottom);
41
if (tls_begin_ != tls_end_)
42
__nsan_set_value_unknown((const u8 *)tls_begin_, tls_end_ - tls_begin_);
43
DTLS *dtls = DTLS_Get();
44
CHECK_NE(dtls, 0);
45
ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) {
46
__nsan_set_value_unknown((const u8 *)dtv.beg, dtv.size);
47
});
48
}
49
50
void NsanThread::Init() {
51
SetThreadStackAndTls();
52
ClearShadowForThreadStackAndTLS();
53
malloc_storage().Init();
54
}
55
56
void NsanThread::TSDDtor(void *tsd) {
57
NsanThread *t = (NsanThread *)tsd;
58
t->Destroy();
59
}
60
61
void NsanThread::Destroy() {
62
malloc_storage().CommitBack();
63
// We also clear the shadow on thread destruction because
64
// some code may still be executing in later TSD destructors
65
// and we don't want it to have any poisoned stack.
66
ClearShadowForThreadStackAndTLS();
67
uptr size = RoundUpTo(sizeof(NsanThread), GetPageSizeCached());
68
UnmapOrDie(this, size);
69
DTLS_Destroy();
70
}
71
72
thread_return_t NsanThread::ThreadStart() {
73
if (!start_routine_) {
74
// start_routine_ == 0 if we're on the main thread or on one of the
75
// OS X libdispatch worker threads. But nobody is supposed to call
76
// ThreadStart() for the worker threads.
77
return 0;
78
}
79
80
return start_routine_(arg_);
81
}
82
83
NsanThread::StackBounds NsanThread::GetStackBounds() const {
84
if (!stack_switching_)
85
return {stack_.bottom, stack_.top};
86
const uptr cur_stack = GET_CURRENT_FRAME();
87
// Note: need to check next stack first, because FinishSwitchFiber
88
// may be in process of overwriting stack_.top/bottom_. But in such case
89
// we are already on the next stack.
90
if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top)
91
return {next_stack_.bottom, next_stack_.top};
92
return {stack_.bottom, stack_.top};
93
}
94
95
uptr NsanThread::stack_top() { return GetStackBounds().top; }
96
97
uptr NsanThread::stack_bottom() { return GetStackBounds().bottom; }
98
99
bool NsanThread::AddrIsInStack(uptr addr) {
100
const auto bounds = GetStackBounds();
101
return addr >= bounds.bottom && addr < bounds.top;
102
}
103
104
void NsanThread::StartSwitchFiber(uptr bottom, uptr size) {
105
CHECK(!stack_switching_);
106
next_stack_.bottom = bottom;
107
next_stack_.top = bottom + size;
108
stack_switching_ = true;
109
}
110
111
void NsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) {
112
CHECK(stack_switching_);
113
if (bottom_old)
114
*bottom_old = stack_.bottom;
115
if (size_old)
116
*size_old = stack_.top - stack_.bottom;
117
stack_.bottom = next_stack_.bottom;
118
stack_.top = next_stack_.top;
119
stack_switching_ = false;
120
next_stack_.top = 0;
121
next_stack_.bottom = 0;
122
}
123
124
static pthread_key_t tsd_key;
125
static bool tsd_key_inited;
126
127
void __nsan::NsanTSDInit(void (*destructor)(void *tsd)) {
128
CHECK(!tsd_key_inited);
129
tsd_key_inited = true;
130
CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
131
}
132
133
static THREADLOCAL NsanThread *nsan_current_thread;
134
135
NsanThread *__nsan::GetCurrentThread() { return nsan_current_thread; }
136
137
void __nsan::SetCurrentThread(NsanThread *t) {
138
// Make sure we do not reset the current NsanThread.
139
CHECK_EQ(0, nsan_current_thread);
140
nsan_current_thread = t;
141
// Make sure that NsanTSDDtor gets called at the end.
142
CHECK(tsd_key_inited);
143
pthread_setspecific(tsd_key, t);
144
}
145
146
void __nsan::NsanTSDDtor(void *tsd) {
147
NsanThread *t = (NsanThread *)tsd;
148
if (t->destructor_iterations_ > 1) {
149
t->destructor_iterations_--;
150
CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
151
return;
152
}
153
nsan_current_thread = nullptr;
154
// Make sure that signal handler can not see a stale current thread pointer.
155
atomic_signal_fence(memory_order_seq_cst);
156
NsanThread::TSDDtor(tsd);
157
}
158
159