xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_thread.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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_internal.h"
190b57cec5SDimitry Andric #include "asan_fake_stack.h"
200b57cec5SDimitry Andric #include "asan_stats.h"
210b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
220b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
230b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_thread_registry.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace __sanitizer {
260b57cec5SDimitry Andric struct DTLS;
270b57cec5SDimitry Andric }  // namespace __sanitizer
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace __asan {
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric class AsanThread;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric // These objects are created for every thread and are never deleted,
340b57cec5SDimitry Andric // so we can find them by tid even if the thread is long dead.
35e8d8bef9SDimitry Andric class AsanThreadContext final : public ThreadContextBase {
360b57cec5SDimitry Andric  public:
370b57cec5SDimitry Andric   explicit AsanThreadContext(int tid)
380b57cec5SDimitry Andric       : ThreadContextBase(tid), announced(false),
390b57cec5SDimitry Andric         destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
400b57cec5SDimitry Andric         thread(nullptr) {}
410b57cec5SDimitry Andric   bool announced;
420b57cec5SDimitry Andric   u8 destructor_iterations;
430b57cec5SDimitry Andric   u32 stack_id;
440b57cec5SDimitry Andric   AsanThread *thread;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   void OnCreated(void *arg) override;
470b57cec5SDimitry Andric   void OnFinished() override;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   struct CreateThreadContextArgs {
500b57cec5SDimitry Andric     AsanThread *thread;
510b57cec5SDimitry Andric     StackTrace *stack;
520b57cec5SDimitry Andric   };
530b57cec5SDimitry Andric };
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric // AsanThreadContext objects are never freed, so we need many of them.
560b57cec5SDimitry Andric COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // AsanThread are stored in TSD and destroyed when the thread dies.
590b57cec5SDimitry Andric class AsanThread {
600b57cec5SDimitry Andric  public:
610b57cec5SDimitry Andric   static AsanThread *Create(thread_callback_t start_routine, void *arg,
620b57cec5SDimitry Andric                             u32 parent_tid, StackTrace *stack, bool detached);
630b57cec5SDimitry Andric   static void TSDDtor(void *tsd);
640b57cec5SDimitry Andric   void Destroy();
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   struct InitOptions;
670b57cec5SDimitry Andric   void Init(const InitOptions *options = nullptr);
680b57cec5SDimitry Andric 
69e8d8bef9SDimitry Andric   thread_return_t ThreadStart(tid_t os_id);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   uptr stack_top();
720b57cec5SDimitry Andric   uptr stack_bottom();
730b57cec5SDimitry Andric   uptr stack_size();
740b57cec5SDimitry Andric   uptr tls_begin() { return tls_begin_; }
750b57cec5SDimitry Andric   uptr tls_end() { return tls_end_; }
760b57cec5SDimitry Andric   DTLS *dtls() { return dtls_; }
770b57cec5SDimitry Andric   u32 tid() { return context_->tid; }
780b57cec5SDimitry Andric   AsanThreadContext *context() { return context_; }
790b57cec5SDimitry Andric   void set_context(AsanThreadContext *context) { context_ = context; }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   struct StackFrameAccess {
820b57cec5SDimitry Andric     uptr offset;
830b57cec5SDimitry Andric     uptr frame_pc;
840b57cec5SDimitry Andric     const char *frame_descr;
850b57cec5SDimitry Andric   };
860b57cec5SDimitry Andric   bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   // Returns a pointer to the start of the stack variable's shadow memory.
890b57cec5SDimitry Andric   uptr GetStackVariableShadowStart(uptr addr);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   bool AddrIsInStack(uptr addr);
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   void DeleteFakeStack(int tid) {
940b57cec5SDimitry Andric     if (!fake_stack_) return;
950b57cec5SDimitry Andric     FakeStack *t = fake_stack_;
960b57cec5SDimitry Andric     fake_stack_ = nullptr;
970b57cec5SDimitry Andric     SetTLSFakeStack(nullptr);
980b57cec5SDimitry Andric     t->Destroy(tid);
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size);
1020b57cec5SDimitry Andric   void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
1030b57cec5SDimitry Andric                          uptr *size_old);
1040b57cec5SDimitry Andric 
105*fe6060f1SDimitry Andric   FakeStack *get_fake_stack() {
1060b57cec5SDimitry Andric     if (atomic_load(&stack_switching_, memory_order_relaxed))
1070b57cec5SDimitry Andric       return nullptr;
108*fe6060f1SDimitry Andric     if (reinterpret_cast<uptr>(fake_stack_) <= 1)
109*fe6060f1SDimitry Andric       return nullptr;
110*fe6060f1SDimitry Andric     return fake_stack_;
111*fe6060f1SDimitry Andric   }
112*fe6060f1SDimitry Andric 
113*fe6060f1SDimitry Andric   FakeStack *get_or_create_fake_stack() {
114*fe6060f1SDimitry Andric     if (atomic_load(&stack_switching_, memory_order_relaxed))
115*fe6060f1SDimitry Andric       return nullptr;
116*fe6060f1SDimitry Andric     if (reinterpret_cast<uptr>(fake_stack_) <= 1)
1170b57cec5SDimitry Andric       return AsyncSignalSafeLazyInitFakeStack();
1180b57cec5SDimitry Andric     return fake_stack_;
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // True is this thread is currently unwinding stack (i.e. collecting a stack
1220b57cec5SDimitry Andric   // trace). Used to prevent deadlocks on platforms where libc unwinder calls
1230b57cec5SDimitry Andric   // malloc internally. See PR17116 for more details.
1240b57cec5SDimitry Andric   bool isUnwinding() const { return unwinding_; }
1250b57cec5SDimitry Andric   void setUnwinding(bool b) { unwinding_ = b; }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
1280b57cec5SDimitry Andric   AsanStats &stats() { return stats_; }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   void *extra_spill_area() { return &extra_spill_area_; }
1310b57cec5SDimitry Andric 
132e8d8bef9SDimitry Andric   void *get_arg() { return arg_; }
133e8d8bef9SDimitry Andric 
1340b57cec5SDimitry Andric  private:
1350b57cec5SDimitry Andric   // NOTE: There is no AsanThread constructor. It is allocated
1360b57cec5SDimitry Andric   // via mmap() and *must* be valid in zero-initialized state.
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   void SetThreadStackAndTls(const InitOptions *options);
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   void ClearShadowForThreadStackAndTLS();
1410b57cec5SDimitry Andric   FakeStack *AsyncSignalSafeLazyInitFakeStack();
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   struct StackBounds {
1440b57cec5SDimitry Andric     uptr bottom;
1450b57cec5SDimitry Andric     uptr top;
1460b57cec5SDimitry Andric   };
1470b57cec5SDimitry Andric   StackBounds GetStackBounds() const;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   AsanThreadContext *context_;
1500b57cec5SDimitry Andric   thread_callback_t start_routine_;
1510b57cec5SDimitry Andric   void *arg_;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   uptr stack_top_;
1540b57cec5SDimitry Andric   uptr stack_bottom_;
1550b57cec5SDimitry Andric   // these variables are used when the thread is about to switch stack
1560b57cec5SDimitry Andric   uptr next_stack_top_;
1570b57cec5SDimitry Andric   uptr next_stack_bottom_;
1580b57cec5SDimitry Andric   // true if switching is in progress
1590b57cec5SDimitry Andric   atomic_uint8_t stack_switching_;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   uptr tls_begin_;
1620b57cec5SDimitry Andric   uptr tls_end_;
1630b57cec5SDimitry Andric   DTLS *dtls_;
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   FakeStack *fake_stack_;
1660b57cec5SDimitry Andric   AsanThreadLocalMallocStorage malloc_storage_;
1670b57cec5SDimitry Andric   AsanStats stats_;
1680b57cec5SDimitry Andric   bool unwinding_;
1690b57cec5SDimitry Andric   uptr extra_spill_area_;
1700b57cec5SDimitry Andric };
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric // Returns a single instance of registry.
1730b57cec5SDimitry Andric ThreadRegistry &asanThreadRegistry();
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric // Must be called under ThreadRegistryLock.
1760b57cec5SDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric // Get the current thread. May return 0.
1790b57cec5SDimitry Andric AsanThread *GetCurrentThread();
1800b57cec5SDimitry Andric void SetCurrentThread(AsanThread *t);
1810b57cec5SDimitry Andric u32 GetCurrentTidOrInvalid();
1820b57cec5SDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr);
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric // Used to handle fork().
1850b57cec5SDimitry Andric void EnsureMainThreadIDIsCorrect();
1860b57cec5SDimitry Andric } // namespace __asan
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric #endif // ASAN_THREAD_H
189