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 | uptr stack_size = 0; |
54 | uptr tls_size = 0; |
55 | GetThreadStackAndTls(main: tid == kMainTid, stk_addr: &args.stack_begin, stk_size: &stack_size, |
56 | tls_addr: &args.tls_begin, tls_size: &tls_size); |
57 | args.stack_end = args.stack_begin + stack_size; |
58 | args.tls_end = args.tls_begin + tls_size; |
59 | GetAllocatorCacheRange(begin: &args.cache_begin, end: &args.cache_end); |
60 | args.dtls = DTLS_Get(); |
61 | ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, onstarted_arg: &args); |
62 | } |
63 | |
64 | bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, |
65 | uptr *tls_begin, uptr *tls_end, uptr *cache_begin, |
66 | uptr *cache_end, DTLS **dtls) { |
67 | ThreadContext *context = static_cast<ThreadContext *>( |
68 | GetLsanThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id)); |
69 | if (!context) |
70 | return false; |
71 | *stack_begin = context->stack_begin(); |
72 | *stack_end = context->stack_end(); |
73 | *tls_begin = context->tls_begin(); |
74 | *tls_end = context->tls_end(); |
75 | *cache_begin = context->cache_begin(); |
76 | *cache_end = context->cache_end(); |
77 | *dtls = context->dtls(); |
78 | return true; |
79 | } |
80 | |
81 | void InitializeMainThread() { |
82 | u32 tid = ThreadCreate(tid: kMainTid, detached: true); |
83 | CHECK_EQ(tid, kMainTid); |
84 | ThreadStart(tid, os_id: GetTid()); |
85 | } |
86 | |
87 | static void OnStackUnwind(const SignalContext &sig, const void *, |
88 | BufferedStackTrace *stack) { |
89 | stack->Unwind(pc: StackTrace::GetNextInstructionPc(pc: sig.pc), bp: sig.bp, context: sig.context, |
90 | request_fast: common_flags()->fast_unwind_on_fatal); |
91 | } |
92 | |
93 | void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { |
94 | HandleDeadlySignal(siginfo, context, tid: GetCurrentThreadId(), unwind: &OnStackUnwind, |
95 | unwind_context: nullptr); |
96 | } |
97 | |
98 | void InstallAtExitCheckLeaks() { |
99 | if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) |
100 | Atexit(function: DoLeakCheck); |
101 | } |
102 | |
103 | static void BeforeFork() { |
104 | LockGlobal(); |
105 | LockThreads(); |
106 | LockAllocator(); |
107 | StackDepotLockBeforeFork(); |
108 | } |
109 | |
110 | static void AfterFork(bool fork_child) { |
111 | StackDepotUnlockAfterFork(fork_child); |
112 | UnlockAllocator(); |
113 | UnlockThreads(); |
114 | UnlockGlobal(); |
115 | } |
116 | |
117 | void InstallAtForkHandler() { |
118 | # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE |
119 | return; // FIXME: Implement FutexWait. |
120 | # endif |
121 | pthread_atfork( |
122 | prepare: &BeforeFork, parent: []() { AfterFork(/* fork_child= */ false); }, |
123 | child: []() { AfterFork(/* fork_child= */ true); }); |
124 | } |
125 | |
126 | } // namespace __lsan |
127 | |
128 | #endif // SANITIZER_POSIX |
129 | |