137 lines · cpp
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-exception6//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_FUCHSIA17#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 __sanitizer28 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 before40// the thread itself has started running.41void ThreadContext::OnCreated(void *arg) {42 // Stack bounds passed through from __sanitizer_before_thread_create_hook43 // 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 __lsan94 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, in99// 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_FUCHSIA137