| 1 | //=-- lsan_posix.cpp -----------------------------------------------------===// |
| 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 LeakSanitizer. |
| 10 | // Standalone LSan RTL code common to POSIX-like systems. |
| 11 | // |
| 12 | //===---------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "sanitizer_common/sanitizer_platform.h" |
| 15 | |
| 16 | #if SANITIZER_POSIX |
| 17 | # include <pthread.h> |
| 18 | |
| 19 | # include "lsan.h" |
| 20 | # include "lsan_allocator.h" |
| 21 | # include "lsan_thread.h" |
| 22 | # include "sanitizer_common/sanitizer_stacktrace.h" |
| 23 | # include "sanitizer_common/sanitizer_tls_get_addr.h" |
| 24 | |
| 25 | namespace __lsan { |
| 26 | |
| 27 | ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} |
| 28 | |
| 29 | struct OnStartedArgs { |
| 30 | uptr stack_begin; |
| 31 | uptr stack_end; |
| 32 | uptr cache_begin; |
| 33 | uptr cache_end; |
| 34 | uptr tls_begin; |
| 35 | uptr tls_end; |
| 36 | DTLS *dtls; |
| 37 | }; |
| 38 | |
| 39 | void ThreadContext::OnStarted(void *arg) { |
| 40 | ThreadContextLsanBase::OnStarted(arg); |
| 41 | auto args = reinterpret_cast<const OnStartedArgs *>(arg); |
| 42 | stack_begin_ = args->stack_begin; |
| 43 | stack_end_ = args->stack_end; |
| 44 | tls_begin_ = args->tls_begin; |
| 45 | tls_end_ = args->tls_end; |
| 46 | cache_begin_ = args->cache_begin; |
| 47 | cache_end_ = args->cache_end; |
| 48 | dtls_ = args->dtls; |
| 49 | } |
| 50 | |
| 51 | void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { |
| 52 | OnStartedArgs args; |
| 53 | GetThreadStackAndTls(main: tid == kMainTid, stk_begin: &args.stack_begin, stk_end: &args.stack_end, |
| 54 | tls_begin: &args.tls_begin, tls_end: &args.tls_end); |
| 55 | GetAllocatorCacheRange(begin: &args.cache_begin, end: &args.cache_end); |
| 56 | args.dtls = DTLS_Get(); |
| 57 | ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, onstarted_arg: &args); |
| 58 | } |
| 59 | |
| 60 | bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, |
| 61 | uptr *tls_begin, uptr *tls_end, uptr *cache_begin, |
| 62 | uptr *cache_end, DTLS **dtls) { |
| 63 | ThreadContext *context = static_cast<ThreadContext *>( |
| 64 | GetLsanThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id)); |
| 65 | if (!context) |
| 66 | return false; |
| 67 | *stack_begin = context->stack_begin(); |
| 68 | *stack_end = context->stack_end(); |
| 69 | *tls_begin = context->tls_begin(); |
| 70 | *tls_end = context->tls_end(); |
| 71 | *cache_begin = context->cache_begin(); |
| 72 | *cache_end = context->cache_end(); |
| 73 | *dtls = context->dtls(); |
| 74 | return true; |
| 75 | } |
| 76 | |
| 77 | void InitializeMainThread() { |
| 78 | u32 tid = ThreadCreate(tid: kMainTid, detached: true); |
| 79 | CHECK_EQ(tid, kMainTid); |
| 80 | ThreadStart(tid, os_id: GetTid()); |
| 81 | } |
| 82 | |
| 83 | static void OnStackUnwind(const SignalContext &sig, const void *, |
| 84 | BufferedStackTrace *stack) { |
| 85 | stack->Unwind(pc: StackTrace::GetNextInstructionPc(pc: sig.pc), bp: sig.bp, context: sig.context, |
| 86 | request_fast: common_flags()->fast_unwind_on_fatal); |
| 87 | } |
| 88 | |
| 89 | void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { |
| 90 | HandleDeadlySignal(siginfo, context, tid: GetCurrentThreadId(), unwind: &OnStackUnwind, |
| 91 | unwind_context: nullptr); |
| 92 | } |
| 93 | |
| 94 | void InstallAtExitCheckLeaks() { |
| 95 | if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) |
| 96 | Atexit(function: DoLeakCheck); |
| 97 | } |
| 98 | |
| 99 | static void BeforeFork() { |
| 100 | VReport(2, "BeforeFork tid: %llu\n" , GetTid()); |
| 101 | LockGlobal(); |
| 102 | LockThreads(); |
| 103 | LockAllocator(); |
| 104 | StackDepotLockBeforeFork(); |
| 105 | } |
| 106 | |
| 107 | static void AfterFork(bool fork_child) { |
| 108 | StackDepotUnlockAfterFork(fork_child); |
| 109 | UnlockAllocator(); |
| 110 | UnlockThreads(); |
| 111 | UnlockGlobal(); |
| 112 | VReport(2, "AfterFork tid: %llu\n" , GetTid()); |
| 113 | } |
| 114 | |
| 115 | void InstallAtForkHandler() { |
| 116 | # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE |
| 117 | return; // FIXME: Implement FutexWait. |
| 118 | # endif |
| 119 | pthread_atfork( |
| 120 | prepare: &BeforeFork, parent: []() { AfterFork(/* fork_child= */ false); }, |
| 121 | child: []() { AfterFork(/* fork_child= */ true); }); |
| 122 | } |
| 123 | |
| 124 | } // namespace __lsan |
| 125 | |
| 126 | #endif // SANITIZER_POSIX |
| 127 | |