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
LsanOnDeadlySignal(int signo,void * siginfo,void * context)26 void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
27
ThreadContext(int tid)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.
OnCreated(void * arg)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
OnStarted(void * arg)48 void ThreadContext::OnStarted(void *arg) {
49 ThreadContextLsanBase::OnStarted(arg);
50 auto args = reinterpret_cast<const OnStartedArgs *>(arg);
51 cache_begin_ = args->cache_begin;
52 cache_end_ = args->cache_end;
53 }
54
ThreadStart(u32 tid)55 void ThreadStart(u32 tid) {
56 OnStartedArgs args;
57 GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
58 CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
59 ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
60 }
61
InitializeMainThread()62 void InitializeMainThread() {
63 OnCreatedArgs args;
64 __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
65 &args.stack_begin);
66 u32 tid = ThreadCreate(kMainTid, true, &args);
67 CHECK_EQ(tid, 0);
68 ThreadStart(tid);
69 }
70
GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> * caches)71 void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
72 GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
73 [](ThreadContextBase *tctx, void *arg) {
74 auto ctx = static_cast<ThreadContext *>(tctx);
75 static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
76 },
77 caches);
78 }
79
80 // On Fuchsia, leak detection is done by a special hook after atexit hooks.
81 // So this doesn't install any atexit hook like on other platforms.
InstallAtExitCheckLeaks()82 void InstallAtExitCheckLeaks() {}
InstallAtForkHandler()83 void InstallAtForkHandler() {}
84
85 // ASan defines this to check its `halt_on_error` flag.
UseExitcodeOnLeak()86 bool UseExitcodeOnLeak() { return true; }
87
88 } // namespace __lsan
89
90 // These are declared (in extern "C") by <zircon/sanitizer.h>.
91 // The system runtime will call our definitions directly.
92
93 // This is called before each thread creation is attempted. So, in
94 // its first call, the calling thread is the initial and sole thread.
__sanitizer_before_thread_create_hook(thrd_t thread,bool detached,const char * name,void * stack_base,size_t stack_size)95 void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
96 const char *name, void *stack_base,
97 size_t stack_size) {
98 ENSURE_LSAN_INITED;
99 EnsureMainThreadIDIsCorrect();
100 OnCreatedArgs args;
101 args.stack_begin = reinterpret_cast<uptr>(stack_base);
102 args.stack_end = args.stack_begin + stack_size;
103 u32 parent_tid = GetCurrentThreadId();
104 u32 tid = ThreadCreate(parent_tid, detached, &args);
105 return reinterpret_cast<void *>(static_cast<uptr>(tid));
106 }
107
108 // This is called after creating a new thread (in the creating thread),
109 // with the pointer returned by __sanitizer_before_thread_create_hook (above).
__sanitizer_thread_create_hook(void * hook,thrd_t thread,int error)110 void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
111 u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
112 // On success, there is nothing to do here.
113 if (error != thrd_success) {
114 // Clean up the thread registry for the thread creation that didn't happen.
115 GetLsanThreadRegistryLocked()->FinishThread(tid);
116 }
117 }
118
119 // This is called in the newly-created thread before it runs anything else,
120 // with the pointer returned by __sanitizer_before_thread_create_hook (above).
__sanitizer_thread_start_hook(void * hook,thrd_t self)121 void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
122 u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
123 ThreadStart(tid);
124 }
125
126 // Each thread runs this just before it exits,
127 // with the pointer returned by BeforeThreadCreateHook (above).
128 // All per-thread destructors have already been called.
__sanitizer_thread_exit_hook(void * hook,thrd_t self)129 void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
130
131 #endif // SANITIZER_FUCHSIA
132