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
22using namespace __lsan;
23
24namespace __sanitizer {
25// LSan doesn't need to do anything else special in the startup hook.
26void EarlySanitizerInit() {}
27} // namespace __sanitizer
28
29namespace __lsan {
30
31void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
32
33ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
34
35struct 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.
41void 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
49struct OnStartedArgs {
50 uptr cache_begin, cache_end;
51};
52
53void 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
60void 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
67void 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
76void 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.
87void InstallAtExitCheckLeaks() {}
88void InstallAtForkHandler() {}
89
90// ASan defines this to check its `halt_on_error` flag.
91bool 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.
100void *__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).
115void __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).
126void __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.
134void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
135
136#endif // SANITIZER_FUCHSIA
137