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
26namespace __sanitizer {
27struct DTLS;
28} // namespace __sanitizer
29
30namespace __asan {
31
32class 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.
36class 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.
57COMPILER_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.
67class 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 *extra_spill_area() { 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 extra_spill_area_;
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.
200ThreadRegistry &asanThreadRegistry();
201ThreadArgRetval &asanThreadArgRetval();
202
203// Must be called under ThreadRegistryLock.
204AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
205
206// Get the current thread. May return 0.
207AsanThread *GetCurrentThread();
208void SetCurrentThread(AsanThread *t);
209u32 GetCurrentTidOrInvalid();
210AsanThread *FindThreadByStackAddress(uptr addr);
211
212// Used to handle fork().
213void EnsureMainThreadIDIsCorrect();
214} // namespace __asan
215
216#endif // ASAN_THREAD_H
217