xref: /freebsd/contrib/llvm-project/compiler-rt/lib/lsan/lsan_fuchsia.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
1 //=-- lsan_fuchsia.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 specific to Fuchsia.
11 //
12 //===---------------------------------------------------------------------===//
13 
14 #include "sanitizer_common/sanitizer_platform.h"
15 
16 #if SANITIZER_FUCHSIA
17 #include <zircon/sanitizer.h>
18 
19 #include "lsan.h"
20 #include "lsan_allocator.h"
21 
22 using namespace __lsan;
23 
24 namespace __sanitizer {
25 // LSan doesn't need to do anything else special in the startup hook.
26 void EarlySanitizerInit() {}
27 }  // namespace __sanitizer
28 
29 namespace __lsan {
30 
31 void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
32 
33 ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
34 
35 struct OnCreatedArgs {
36   uptr stack_begin, stack_end;
37 };
38 
39 // On Fuchsia, the stack bounds of a new thread are available before
40 // the thread itself has started running.
41 void ThreadContext::OnCreated(void *arg) {
42   // Stack bounds passed through from __sanitizer_before_thread_create_hook
43   // or InitializeMainThread.
44   auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
45   stack_begin_ = args->stack_begin;
46   stack_end_ = args->stack_end;
47 }
48 
49 struct OnStartedArgs {
50   uptr cache_begin, cache_end;
51 };
52 
53 void ThreadContext::OnStarted(void *arg) {
54   ThreadContextLsanBase::OnStarted(arg);
55   auto args = reinterpret_cast<const OnStartedArgs *>(arg);
56   cache_begin_ = args->cache_begin;
57   cache_end_ = args->cache_end;
58 }
59 
60 void ThreadStart(u32 tid) {
61   OnStartedArgs args;
62   GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
63   CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
64   ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
65 }
66 
67 void InitializeMainThread() {
68   OnCreatedArgs args;
69   __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
70                                           &args.stack_begin);
71   u32 tid = ThreadCreate(kMainTid, true, &args);
72   CHECK_EQ(tid, 0);
73   ThreadStart(tid);
74 }
75 
76 void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
77   GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
78       [](ThreadContextBase *tctx, void *arg) {
79         auto ctx = static_cast<ThreadContext *>(tctx);
80         static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
81       },
82       caches);
83 }
84 
85 // On Fuchsia, leak detection is done by a special hook after atexit hooks.
86 // So this doesn't install any atexit hook like on other platforms.
87 void InstallAtExitCheckLeaks() {}
88 void InstallAtForkHandler() {}
89 
90 // ASan defines this to check its `halt_on_error` flag.
91 bool UseExitcodeOnLeak() { return true; }
92 
93 }  // namespace __lsan
94 
95 // These are declared (in extern "C") by <zircon/sanitizer.h>.
96 // The system runtime will call our definitions directly.
97 
98 // This is called before each thread creation is attempted.  So, in
99 // its first call, the calling thread is the initial and sole thread.
100 void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
101                                             const char *name, void *stack_base,
102                                             size_t stack_size) {
103   ENSURE_LSAN_INITED;
104   EnsureMainThreadIDIsCorrect();
105   OnCreatedArgs args;
106   args.stack_begin = reinterpret_cast<uptr>(stack_base);
107   args.stack_end = args.stack_begin + stack_size;
108   u32 parent_tid = GetCurrentThreadId();
109   u32 tid = ThreadCreate(parent_tid, detached, &args);
110   return reinterpret_cast<void *>(static_cast<uptr>(tid));
111 }
112 
113 // This is called after creating a new thread (in the creating thread),
114 // with the pointer returned by __sanitizer_before_thread_create_hook (above).
115 void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
116   u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
117   // On success, there is nothing to do here.
118   if (error != thrd_success) {
119     // Clean up the thread registry for the thread creation that didn't happen.
120     GetLsanThreadRegistryLocked()->FinishThread(tid);
121   }
122 }
123 
124 // This is called in the newly-created thread before it runs anything else,
125 // with the pointer returned by __sanitizer_before_thread_create_hook (above).
126 void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
127   u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
128   ThreadStart(tid);
129 }
130 
131 // Each thread runs this just before it exits,
132 // with the pointer returned by BeforeThreadCreateHook (above).
133 // All per-thread destructors have already been called.
134 void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
135 
136 #endif  // SANITIZER_FUCHSIA
137