//=-- lsan_fuchsia.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===---------------------------------------------------------------------===// // // This file is a part of LeakSanitizer. // Standalone LSan RTL code specific to Fuchsia. // //===---------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FUCHSIA #include #include "lsan.h" #include "lsan_allocator.h" using namespace __lsan; namespace __lsan { void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {} ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} struct OnCreatedArgs { uptr stack_begin, stack_end; }; // On Fuchsia, the stack bounds of a new thread are available before // the thread itself has started running. void ThreadContext::OnCreated(void *arg) { // Stack bounds passed through from __sanitizer_before_thread_create_hook // or InitializeMainThread. auto args = reinterpret_cast(arg); stack_begin_ = args->stack_begin; stack_end_ = args->stack_end; } struct OnStartedArgs { uptr cache_begin, cache_end; }; void ThreadContext::OnStarted(void *arg) { auto args = reinterpret_cast(arg); cache_begin_ = args->cache_begin; cache_end_ = args->cache_end; } void ThreadStart(u32 tid) { OnStartedArgs args; GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache)); ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args); } void InitializeMainThread() { OnCreatedArgs args; __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end, &args.stack_begin); u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args); CHECK_EQ(tid, 0); ThreadStart(tid); } void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) { GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( [](ThreadContextBase *tctx, void *arg) { auto ctx = static_cast(tctx); static_cast(arg)->push_back(ctx->cache_begin()); }, caches); } } // namespace __lsan // These are declared (in extern "C") by . // The system runtime will call our definitions directly. // This is called before each thread creation is attempted. So, in // its first call, the calling thread is the initial and sole thread. void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, const char *name, void *stack_base, size_t stack_size) { uptr user_id = reinterpret_cast(thread); ENSURE_LSAN_INITED; EnsureMainThreadIDIsCorrect(); OnCreatedArgs args; args.stack_begin = reinterpret_cast(stack_base); args.stack_end = args.stack_begin + stack_size; u32 parent_tid = GetCurrentThread(); u32 tid = ThreadCreate(parent_tid, user_id, detached, &args); return reinterpret_cast(static_cast(tid)); } // This is called after creating a new thread (in the creating thread), // with the pointer returned by __sanitizer_before_thread_create_hook (above). void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { u32 tid = static_cast(reinterpret_cast(hook)); // On success, there is nothing to do here. if (error != thrd_success) { // Clean up the thread registry for the thread creation that didn't happen. GetThreadRegistryLocked()->FinishThread(tid); } } // This is called in the newly-created thread before it runs anything else, // with the pointer returned by __sanitizer_before_thread_create_hook (above). void __sanitizer_thread_start_hook(void *hook, thrd_t self) { u32 tid = static_cast(reinterpret_cast(hook)); ThreadStart(tid); } // Each thread runs this just before it exits, // with the pointer returned by BeforeThreadCreateHook (above). // All per-thread destructors have already been called. void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); } #endif // SANITIZER_FUCHSIA