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