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 __lsan { 25 26void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {} 27 28ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} 29 30struct 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. 36void 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 44struct OnStartedArgs { 45 uptr cache_begin, cache_end; 46}; 47 48void 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 55void 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 62void 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 71void 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. 82void InstallAtExitCheckLeaks() {} 83void InstallAtForkHandler() {} 84 85// ASan defines this to check its `halt_on_error` flag. 86bool 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. 95void *__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). 110void __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). 121void __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. 129void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); } 130 131#endif // SANITIZER_FUCHSIA 132