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