xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_thread.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===-- asan_thread.h -------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
100b57cec5SDimitry Andric //
1168d75effSDimitry Andric // ASan-private header for asan_thread.cpp.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef ASAN_THREAD_H
150b57cec5SDimitry Andric #define ASAN_THREAD_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "asan_allocator.h"
180b57cec5SDimitry Andric #include "asan_fake_stack.h"
1906c3fb27SDimitry Andric #include "asan_internal.h"
200b57cec5SDimitry Andric #include "asan_stats.h"
210b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
220b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
2306c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_thread_arg_retval.h"
240b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_thread_registry.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric namespace __sanitizer {
270b57cec5SDimitry Andric struct DTLS;
280b57cec5SDimitry Andric }  // namespace __sanitizer
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric namespace __asan {
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric class AsanThread;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric // These objects are created for every thread and are never deleted,
350b57cec5SDimitry Andric // so we can find them by tid even if the thread is long dead.
36e8d8bef9SDimitry Andric class AsanThreadContext final : public ThreadContextBase {
370b57cec5SDimitry Andric  public:
380b57cec5SDimitry Andric   explicit AsanThreadContext(int tid)
390b57cec5SDimitry Andric       : ThreadContextBase(tid), announced(false),
400b57cec5SDimitry Andric         destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
410b57cec5SDimitry Andric         thread(nullptr) {}
420b57cec5SDimitry Andric   bool announced;
430b57cec5SDimitry Andric   u8 destructor_iterations;
440b57cec5SDimitry Andric   u32 stack_id;
450b57cec5SDimitry Andric   AsanThread *thread;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   void OnCreated(void *arg) override;
480b57cec5SDimitry Andric   void OnFinished() override;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   struct CreateThreadContextArgs {
510b57cec5SDimitry Andric     AsanThread *thread;
520b57cec5SDimitry Andric     StackTrace *stack;
530b57cec5SDimitry Andric   };
540b57cec5SDimitry Andric };
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric // AsanThreadContext objects are never freed, so we need many of them.
570b57cec5SDimitry Andric COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
580b57cec5SDimitry Andric 
59*5f757f3fSDimitry Andric #if defined(_MSC_VER) && !defined(__clang__)
60*5f757f3fSDimitry Andric // MSVC raises a warning about a nonstandard extension being used for the 0
61*5f757f3fSDimitry Andric // sized element in this array. Disable this for warn-as-error builds.
62*5f757f3fSDimitry Andric #  pragma warning(push)
63*5f757f3fSDimitry Andric #  pragma warning(disable : 4200)
64*5f757f3fSDimitry Andric #endif
65*5f757f3fSDimitry Andric 
660b57cec5SDimitry Andric // AsanThread are stored in TSD and destroyed when the thread dies.
670b57cec5SDimitry Andric class AsanThread {
680b57cec5SDimitry Andric  public:
69*5f757f3fSDimitry Andric   template <typename T>
70*5f757f3fSDimitry Andric   static AsanThread *Create(const T &data, u32 parent_tid, StackTrace *stack,
71*5f757f3fSDimitry Andric                             bool detached) {
72*5f757f3fSDimitry Andric     return Create(&data, sizeof(data), parent_tid, stack, detached);
73*5f757f3fSDimitry Andric   }
74*5f757f3fSDimitry Andric   static AsanThread *Create(u32 parent_tid, StackTrace *stack, bool detached) {
75*5f757f3fSDimitry Andric     return Create(nullptr, 0, parent_tid, stack, detached);
76*5f757f3fSDimitry Andric   }
770b57cec5SDimitry Andric   static void TSDDtor(void *tsd);
780b57cec5SDimitry Andric   void Destroy();
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   struct InitOptions;
810b57cec5SDimitry Andric   void Init(const InitOptions *options = nullptr);
820b57cec5SDimitry Andric 
83*5f757f3fSDimitry Andric   void ThreadStart(tid_t os_id);
84*5f757f3fSDimitry Andric   thread_return_t RunThread();
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   uptr stack_top();
870b57cec5SDimitry Andric   uptr stack_bottom();
880b57cec5SDimitry Andric   uptr stack_size();
890b57cec5SDimitry Andric   uptr tls_begin() { return tls_begin_; }
900b57cec5SDimitry Andric   uptr tls_end() { return tls_end_; }
910b57cec5SDimitry Andric   DTLS *dtls() { return dtls_; }
920b57cec5SDimitry Andric   u32 tid() { return context_->tid; }
930b57cec5SDimitry Andric   AsanThreadContext *context() { return context_; }
940b57cec5SDimitry Andric   void set_context(AsanThreadContext *context) { context_ = context; }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   struct StackFrameAccess {
970b57cec5SDimitry Andric     uptr offset;
980b57cec5SDimitry Andric     uptr frame_pc;
990b57cec5SDimitry Andric     const char *frame_descr;
1000b57cec5SDimitry Andric   };
1010b57cec5SDimitry Andric   bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // Returns a pointer to the start of the stack variable's shadow memory.
1040b57cec5SDimitry Andric   uptr GetStackVariableShadowStart(uptr addr);
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   bool AddrIsInStack(uptr addr);
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   void DeleteFakeStack(int tid) {
1090b57cec5SDimitry Andric     if (!fake_stack_) return;
1100b57cec5SDimitry Andric     FakeStack *t = fake_stack_;
1110b57cec5SDimitry Andric     fake_stack_ = nullptr;
1120b57cec5SDimitry Andric     SetTLSFakeStack(nullptr);
1130b57cec5SDimitry Andric     t->Destroy(tid);
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size);
1170b57cec5SDimitry Andric   void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
1180b57cec5SDimitry Andric                          uptr *size_old);
1190b57cec5SDimitry Andric 
120fe6060f1SDimitry Andric   FakeStack *get_fake_stack() {
1210b57cec5SDimitry Andric     if (atomic_load(&stack_switching_, memory_order_relaxed))
1220b57cec5SDimitry Andric       return nullptr;
123fe6060f1SDimitry Andric     if (reinterpret_cast<uptr>(fake_stack_) <= 1)
124fe6060f1SDimitry Andric       return nullptr;
125fe6060f1SDimitry Andric     return fake_stack_;
126fe6060f1SDimitry Andric   }
127fe6060f1SDimitry Andric 
128fe6060f1SDimitry Andric   FakeStack *get_or_create_fake_stack() {
129fe6060f1SDimitry Andric     if (atomic_load(&stack_switching_, memory_order_relaxed))
130fe6060f1SDimitry Andric       return nullptr;
131fe6060f1SDimitry Andric     if (reinterpret_cast<uptr>(fake_stack_) <= 1)
1320b57cec5SDimitry Andric       return AsyncSignalSafeLazyInitFakeStack();
1330b57cec5SDimitry Andric     return fake_stack_;
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   // True is this thread is currently unwinding stack (i.e. collecting a stack
1370b57cec5SDimitry Andric   // trace). Used to prevent deadlocks on platforms where libc unwinder calls
1380b57cec5SDimitry Andric   // malloc internally. See PR17116 for more details.
1390b57cec5SDimitry Andric   bool isUnwinding() const { return unwinding_; }
1400b57cec5SDimitry Andric   void setUnwinding(bool b) { unwinding_ = b; }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
1430b57cec5SDimitry Andric   AsanStats &stats() { return stats_; }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   void *extra_spill_area() { return &extra_spill_area_; }
1460b57cec5SDimitry Andric 
147*5f757f3fSDimitry Andric   template <typename T>
148*5f757f3fSDimitry Andric   void GetStartData(T &data) const {
149*5f757f3fSDimitry Andric     GetStartData(&data, sizeof(data));
150*5f757f3fSDimitry Andric   }
151e8d8bef9SDimitry Andric 
1520b57cec5SDimitry Andric  private:
1530b57cec5SDimitry Andric   // NOTE: There is no AsanThread constructor. It is allocated
1540b57cec5SDimitry Andric   // via mmap() and *must* be valid in zero-initialized state.
1550b57cec5SDimitry Andric 
156*5f757f3fSDimitry Andric   static AsanThread *Create(const void *start_data, uptr data_size,
157*5f757f3fSDimitry Andric                             u32 parent_tid, StackTrace *stack, bool detached);
158*5f757f3fSDimitry Andric 
1590b57cec5SDimitry Andric   void SetThreadStackAndTls(const InitOptions *options);
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   void ClearShadowForThreadStackAndTLS();
1620b57cec5SDimitry Andric   FakeStack *AsyncSignalSafeLazyInitFakeStack();
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   struct StackBounds {
1650b57cec5SDimitry Andric     uptr bottom;
1660b57cec5SDimitry Andric     uptr top;
1670b57cec5SDimitry Andric   };
1680b57cec5SDimitry Andric   StackBounds GetStackBounds() const;
1690b57cec5SDimitry Andric 
170*5f757f3fSDimitry Andric   void GetStartData(void *out, uptr out_size) const;
171*5f757f3fSDimitry Andric 
1720b57cec5SDimitry Andric   AsanThreadContext *context_;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   uptr stack_top_;
1750b57cec5SDimitry Andric   uptr stack_bottom_;
1760b57cec5SDimitry Andric   // these variables are used when the thread is about to switch stack
1770b57cec5SDimitry Andric   uptr next_stack_top_;
1780b57cec5SDimitry Andric   uptr next_stack_bottom_;
1790b57cec5SDimitry Andric   // true if switching is in progress
1800b57cec5SDimitry Andric   atomic_uint8_t stack_switching_;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   uptr tls_begin_;
1830b57cec5SDimitry Andric   uptr tls_end_;
1840b57cec5SDimitry Andric   DTLS *dtls_;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   FakeStack *fake_stack_;
1870b57cec5SDimitry Andric   AsanThreadLocalMallocStorage malloc_storage_;
1880b57cec5SDimitry Andric   AsanStats stats_;
1890b57cec5SDimitry Andric   bool unwinding_;
1900b57cec5SDimitry Andric   uptr extra_spill_area_;
191*5f757f3fSDimitry Andric 
192*5f757f3fSDimitry Andric   char start_data_[];
1930b57cec5SDimitry Andric };
1940b57cec5SDimitry Andric 
195*5f757f3fSDimitry Andric #if defined(_MSC_VER) && !defined(__clang__)
196*5f757f3fSDimitry Andric #  pragma warning(pop)
197*5f757f3fSDimitry Andric #endif
198*5f757f3fSDimitry Andric 
1990b57cec5SDimitry Andric // Returns a single instance of registry.
2000b57cec5SDimitry Andric ThreadRegistry &asanThreadRegistry();
20106c3fb27SDimitry Andric ThreadArgRetval &asanThreadArgRetval();
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric // Must be called under ThreadRegistryLock.
2040b57cec5SDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric // Get the current thread. May return 0.
2070b57cec5SDimitry Andric AsanThread *GetCurrentThread();
2080b57cec5SDimitry Andric void SetCurrentThread(AsanThread *t);
2090b57cec5SDimitry Andric u32 GetCurrentTidOrInvalid();
2100b57cec5SDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr);
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric // Used to handle fork().
2130b57cec5SDimitry Andric void EnsureMainThreadIDIsCorrect();
2140b57cec5SDimitry Andric } // namespace __asan
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric #endif // ASAN_THREAD_H
217