xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_thread.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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"
19*06c3fb27SDimitry 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"
23*06c3fb27SDimitry 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 
590b57cec5SDimitry Andric // AsanThread are stored in TSD and destroyed when the thread dies.
600b57cec5SDimitry Andric class AsanThread {
610b57cec5SDimitry Andric  public:
620b57cec5SDimitry Andric   static AsanThread *Create(thread_callback_t start_routine, void *arg,
630b57cec5SDimitry Andric                             u32 parent_tid, StackTrace *stack, bool detached);
640b57cec5SDimitry Andric   static void TSDDtor(void *tsd);
650b57cec5SDimitry Andric   void Destroy();
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   struct InitOptions;
680b57cec5SDimitry Andric   void Init(const InitOptions *options = nullptr);
690b57cec5SDimitry Andric 
70e8d8bef9SDimitry Andric   thread_return_t ThreadStart(tid_t os_id);
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   uptr stack_top();
730b57cec5SDimitry Andric   uptr stack_bottom();
740b57cec5SDimitry Andric   uptr stack_size();
750b57cec5SDimitry Andric   uptr tls_begin() { return tls_begin_; }
760b57cec5SDimitry Andric   uptr tls_end() { return tls_end_; }
770b57cec5SDimitry Andric   DTLS *dtls() { return dtls_; }
780b57cec5SDimitry Andric   u32 tid() { return context_->tid; }
790b57cec5SDimitry Andric   AsanThreadContext *context() { return context_; }
800b57cec5SDimitry Andric   void set_context(AsanThreadContext *context) { context_ = context; }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   struct StackFrameAccess {
830b57cec5SDimitry Andric     uptr offset;
840b57cec5SDimitry Andric     uptr frame_pc;
850b57cec5SDimitry Andric     const char *frame_descr;
860b57cec5SDimitry Andric   };
870b57cec5SDimitry Andric   bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   // Returns a pointer to the start of the stack variable's shadow memory.
900b57cec5SDimitry Andric   uptr GetStackVariableShadowStart(uptr addr);
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   bool AddrIsInStack(uptr addr);
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   void DeleteFakeStack(int tid) {
950b57cec5SDimitry Andric     if (!fake_stack_) return;
960b57cec5SDimitry Andric     FakeStack *t = fake_stack_;
970b57cec5SDimitry Andric     fake_stack_ = nullptr;
980b57cec5SDimitry Andric     SetTLSFakeStack(nullptr);
990b57cec5SDimitry Andric     t->Destroy(tid);
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size);
1030b57cec5SDimitry Andric   void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
1040b57cec5SDimitry Andric                          uptr *size_old);
1050b57cec5SDimitry Andric 
106fe6060f1SDimitry Andric   FakeStack *get_fake_stack() {
1070b57cec5SDimitry Andric     if (atomic_load(&stack_switching_, memory_order_relaxed))
1080b57cec5SDimitry Andric       return nullptr;
109fe6060f1SDimitry Andric     if (reinterpret_cast<uptr>(fake_stack_) <= 1)
110fe6060f1SDimitry Andric       return nullptr;
111fe6060f1SDimitry Andric     return fake_stack_;
112fe6060f1SDimitry Andric   }
113fe6060f1SDimitry Andric 
114fe6060f1SDimitry Andric   FakeStack *get_or_create_fake_stack() {
115fe6060f1SDimitry Andric     if (atomic_load(&stack_switching_, memory_order_relaxed))
116fe6060f1SDimitry Andric       return nullptr;
117fe6060f1SDimitry Andric     if (reinterpret_cast<uptr>(fake_stack_) <= 1)
1180b57cec5SDimitry Andric       return AsyncSignalSafeLazyInitFakeStack();
1190b57cec5SDimitry Andric     return fake_stack_;
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // True is this thread is currently unwinding stack (i.e. collecting a stack
1230b57cec5SDimitry Andric   // trace). Used to prevent deadlocks on platforms where libc unwinder calls
1240b57cec5SDimitry Andric   // malloc internally. See PR17116 for more details.
1250b57cec5SDimitry Andric   bool isUnwinding() const { return unwinding_; }
1260b57cec5SDimitry Andric   void setUnwinding(bool b) { unwinding_ = b; }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
1290b57cec5SDimitry Andric   AsanStats &stats() { return stats_; }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   void *extra_spill_area() { return &extra_spill_area_; }
1320b57cec5SDimitry Andric 
133*06c3fb27SDimitry Andric   void *get_arg() const { return arg_; }
134e8d8bef9SDimitry Andric 
1350b57cec5SDimitry Andric  private:
1360b57cec5SDimitry Andric   // NOTE: There is no AsanThread constructor. It is allocated
1370b57cec5SDimitry Andric   // via mmap() and *must* be valid in zero-initialized state.
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   void SetThreadStackAndTls(const InitOptions *options);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   void ClearShadowForThreadStackAndTLS();
1420b57cec5SDimitry Andric   FakeStack *AsyncSignalSafeLazyInitFakeStack();
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   struct StackBounds {
1450b57cec5SDimitry Andric     uptr bottom;
1460b57cec5SDimitry Andric     uptr top;
1470b57cec5SDimitry Andric   };
1480b57cec5SDimitry Andric   StackBounds GetStackBounds() const;
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   AsanThreadContext *context_;
1510b57cec5SDimitry Andric   thread_callback_t start_routine_;
1520b57cec5SDimitry Andric   void *arg_;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   uptr stack_top_;
1550b57cec5SDimitry Andric   uptr stack_bottom_;
1560b57cec5SDimitry Andric   // these variables are used when the thread is about to switch stack
1570b57cec5SDimitry Andric   uptr next_stack_top_;
1580b57cec5SDimitry Andric   uptr next_stack_bottom_;
1590b57cec5SDimitry Andric   // true if switching is in progress
1600b57cec5SDimitry Andric   atomic_uint8_t stack_switching_;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   uptr tls_begin_;
1630b57cec5SDimitry Andric   uptr tls_end_;
1640b57cec5SDimitry Andric   DTLS *dtls_;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   FakeStack *fake_stack_;
1670b57cec5SDimitry Andric   AsanThreadLocalMallocStorage malloc_storage_;
1680b57cec5SDimitry Andric   AsanStats stats_;
1690b57cec5SDimitry Andric   bool unwinding_;
1700b57cec5SDimitry Andric   uptr extra_spill_area_;
1710b57cec5SDimitry Andric };
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric // Returns a single instance of registry.
1740b57cec5SDimitry Andric ThreadRegistry &asanThreadRegistry();
175*06c3fb27SDimitry Andric ThreadArgRetval &asanThreadArgRetval();
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric // Must be called under ThreadRegistryLock.
1780b57cec5SDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric // Get the current thread. May return 0.
1810b57cec5SDimitry Andric AsanThread *GetCurrentThread();
1820b57cec5SDimitry Andric void SetCurrentThread(AsanThread *t);
1830b57cec5SDimitry Andric u32 GetCurrentTidOrInvalid();
1840b57cec5SDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr);
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric // Used to handle fork().
1870b57cec5SDimitry Andric void EnsureMainThreadIDIsCorrect();
1880b57cec5SDimitry Andric } // namespace __asan
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric #endif // ASAN_THREAD_H
191