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 | |