1 | //===-- asan_thread.h -------------------------------------------*- C++ -*-===// |
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 | // |
9 | // This file is a part of AddressSanitizer, an address sanity checker. |
10 | // |
11 | // ASan-private header for asan_thread.cpp. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef ASAN_THREAD_H |
15 | #define ASAN_THREAD_H |
16 | |
17 | #include "asan_allocator.h" |
18 | #include "asan_fake_stack.h" |
19 | #include "asan_internal.h" |
20 | #include "asan_stats.h" |
21 | #include "sanitizer_common/sanitizer_common.h" |
22 | #include "sanitizer_common/sanitizer_libc.h" |
23 | #include "sanitizer_common/sanitizer_thread_arg_retval.h" |
24 | #include "sanitizer_common/sanitizer_thread_registry.h" |
25 | |
26 | namespace __sanitizer { |
27 | struct DTLS; |
28 | } // namespace __sanitizer |
29 | |
30 | namespace __asan { |
31 | |
32 | class AsanThread; |
33 | |
34 | // These objects are created for every thread and are never deleted, |
35 | // so we can find them by tid even if the thread is long dead. |
36 | class AsanThreadContext final : public ThreadContextBase { |
37 | public: |
38 | explicit AsanThreadContext(int tid) |
39 | : ThreadContextBase(tid), announced(false), |
40 | destructor_iterations(GetPthreadDestructorIterations()), stack_id(0), |
41 | thread(nullptr) {} |
42 | bool announced; |
43 | u8 destructor_iterations; |
44 | u32 stack_id; |
45 | AsanThread *thread; |
46 | |
47 | void OnCreated(void *arg) override; |
48 | void OnFinished() override; |
49 | |
50 | struct CreateThreadContextArgs { |
51 | AsanThread *thread; |
52 | StackTrace *stack; |
53 | }; |
54 | }; |
55 | |
56 | // AsanThreadContext objects are never freed, so we need many of them. |
57 | COMPILER_CHECK(sizeof(AsanThreadContext) <= 256); |
58 | |
59 | #if defined(_MSC_VER) && !defined(__clang__) |
60 | // MSVC raises a warning about a nonstandard extension being used for the 0 |
61 | // sized element in this array. Disable this for warn-as-error builds. |
62 | # pragma warning(push) |
63 | # pragma warning(disable : 4200) |
64 | #endif |
65 | |
66 | // AsanThread are stored in TSD and destroyed when the thread dies. |
67 | class AsanThread { |
68 | public: |
69 | template <typename T> |
70 | static AsanThread *Create(const T &data, u32 parent_tid, StackTrace *stack, |
71 | bool detached) { |
72 | return Create(&data, sizeof(data), parent_tid, stack, detached); |
73 | } |
74 | static AsanThread *Create(u32 parent_tid, StackTrace *stack, bool detached) { |
75 | return Create(start_data: nullptr, data_size: 0, parent_tid, stack, detached); |
76 | } |
77 | static void TSDDtor(void *tsd); |
78 | void Destroy(); |
79 | |
80 | struct InitOptions; |
81 | void Init(const InitOptions *options = nullptr); |
82 | |
83 | void ThreadStart(tid_t os_id); |
84 | thread_return_t RunThread(); |
85 | |
86 | uptr stack_top(); |
87 | uptr stack_bottom(); |
88 | uptr stack_size(); |
89 | uptr tls_begin() { return tls_begin_; } |
90 | uptr tls_end() { return tls_end_; } |
91 | DTLS *dtls() { return dtls_; } |
92 | u32 tid() { return context_->tid; } |
93 | AsanThreadContext *context() { return context_; } |
94 | void set_context(AsanThreadContext *context) { context_ = context; } |
95 | |
96 | struct StackFrameAccess { |
97 | uptr offset; |
98 | uptr frame_pc; |
99 | const char *frame_descr; |
100 | }; |
101 | bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access); |
102 | |
103 | // Returns a pointer to the start of the stack variable's shadow memory. |
104 | uptr GetStackVariableShadowStart(uptr addr); |
105 | |
106 | bool AddrIsInStack(uptr addr); |
107 | |
108 | void DeleteFakeStack(int tid) { |
109 | if (!fake_stack_) return; |
110 | FakeStack *t = fake_stack_; |
111 | fake_stack_ = nullptr; |
112 | SetTLSFakeStack(nullptr); |
113 | t->Destroy(tid); |
114 | } |
115 | |
116 | void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size); |
117 | void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old, |
118 | uptr *size_old); |
119 | |
120 | FakeStack *get_fake_stack() { |
121 | if (atomic_load(a: &stack_switching_, mo: memory_order_relaxed)) |
122 | return nullptr; |
123 | if (reinterpret_cast<uptr>(fake_stack_) <= 1) |
124 | return nullptr; |
125 | return fake_stack_; |
126 | } |
127 | |
128 | FakeStack *get_or_create_fake_stack() { |
129 | if (atomic_load(a: &stack_switching_, mo: memory_order_relaxed)) |
130 | return nullptr; |
131 | if (reinterpret_cast<uptr>(fake_stack_) <= 1) |
132 | return AsyncSignalSafeLazyInitFakeStack(); |
133 | return fake_stack_; |
134 | } |
135 | |
136 | // True is this thread is currently unwinding stack (i.e. collecting a stack |
137 | // trace). Used to prevent deadlocks on platforms where libc unwinder calls |
138 | // malloc internally. See PR17116 for more details. |
139 | bool isUnwinding() const { return unwinding_; } |
140 | void setUnwinding(bool b) { unwinding_ = b; } |
141 | |
142 | AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } |
143 | AsanStats &stats() { return stats_; } |
144 | |
145 | void *() { return &extra_spill_area_; } |
146 | |
147 | template <typename T> |
148 | void GetStartData(T &data) const { |
149 | GetStartData(&data, sizeof(data)); |
150 | } |
151 | |
152 | private: |
153 | // NOTE: There is no AsanThread constructor. It is allocated |
154 | // via mmap() and *must* be valid in zero-initialized state. |
155 | |
156 | static AsanThread *Create(const void *start_data, uptr data_size, |
157 | u32 parent_tid, StackTrace *stack, bool detached); |
158 | |
159 | void SetThreadStackAndTls(const InitOptions *options); |
160 | |
161 | void ClearShadowForThreadStackAndTLS(); |
162 | FakeStack *AsyncSignalSafeLazyInitFakeStack(); |
163 | |
164 | struct StackBounds { |
165 | uptr bottom; |
166 | uptr top; |
167 | }; |
168 | StackBounds GetStackBounds() const; |
169 | |
170 | void GetStartData(void *out, uptr out_size) const; |
171 | |
172 | AsanThreadContext *context_; |
173 | |
174 | uptr stack_top_; |
175 | uptr stack_bottom_; |
176 | // these variables are used when the thread is about to switch stack |
177 | uptr next_stack_top_; |
178 | uptr next_stack_bottom_; |
179 | // true if switching is in progress |
180 | atomic_uint8_t stack_switching_; |
181 | |
182 | uptr tls_begin_; |
183 | uptr tls_end_; |
184 | DTLS *dtls_; |
185 | |
186 | FakeStack *fake_stack_; |
187 | AsanThreadLocalMallocStorage malloc_storage_; |
188 | AsanStats stats_; |
189 | bool unwinding_; |
190 | uptr ; |
191 | |
192 | char start_data_[]; |
193 | }; |
194 | |
195 | #if defined(_MSC_VER) && !defined(__clang__) |
196 | # pragma warning(pop) |
197 | #endif |
198 | |
199 | // Returns a single instance of registry. |
200 | ThreadRegistry &asanThreadRegistry(); |
201 | ThreadArgRetval &asanThreadArgRetval(); |
202 | |
203 | // Must be called under ThreadRegistryLock. |
204 | AsanThreadContext *GetThreadContextByTidLocked(u32 tid); |
205 | |
206 | // Get the current thread. May return 0. |
207 | AsanThread *GetCurrentThread(); |
208 | void SetCurrentThread(AsanThread *t); |
209 | u32 GetCurrentTidOrInvalid(); |
210 | AsanThread *FindThreadByStackAddress(uptr addr); |
211 | |
212 | // Used to handle fork(). |
213 | void EnsureMainThreadIDIsCorrect(); |
214 | } // namespace __asan |
215 | |
216 | #endif // ASAN_THREAD_H |
217 | |