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