11f9cb04fSpatrick //=-- lsan_fuchsia.cpp ---------------------------------------------------===//
21f9cb04fSpatrick //
31f9cb04fSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41f9cb04fSpatrick // See https://llvm.org/LICENSE.txt for license information.
51f9cb04fSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61f9cb04fSpatrick //
71f9cb04fSpatrick //===---------------------------------------------------------------------===//
81f9cb04fSpatrick //
91f9cb04fSpatrick // This file is a part of LeakSanitizer.
101f9cb04fSpatrick // Standalone LSan RTL code specific to Fuchsia.
111f9cb04fSpatrick //
121f9cb04fSpatrick //===---------------------------------------------------------------------===//
131f9cb04fSpatrick
141f9cb04fSpatrick #include "sanitizer_common/sanitizer_platform.h"
151f9cb04fSpatrick
161f9cb04fSpatrick #if SANITIZER_FUCHSIA
171f9cb04fSpatrick #include <zircon/sanitizer.h>
181f9cb04fSpatrick
191f9cb04fSpatrick #include "lsan.h"
201f9cb04fSpatrick #include "lsan_allocator.h"
211f9cb04fSpatrick
221f9cb04fSpatrick using namespace __lsan;
231f9cb04fSpatrick
241f9cb04fSpatrick namespace __lsan {
251f9cb04fSpatrick
LsanOnDeadlySignal(int signo,void * siginfo,void * context)261f9cb04fSpatrick void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
271f9cb04fSpatrick
ThreadContext(int tid)281f9cb04fSpatrick ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
291f9cb04fSpatrick
301f9cb04fSpatrick struct OnCreatedArgs {
311f9cb04fSpatrick uptr stack_begin, stack_end;
321f9cb04fSpatrick };
331f9cb04fSpatrick
341f9cb04fSpatrick // On Fuchsia, the stack bounds of a new thread are available before
351f9cb04fSpatrick // the thread itself has started running.
OnCreated(void * arg)361f9cb04fSpatrick void ThreadContext::OnCreated(void *arg) {
371f9cb04fSpatrick // Stack bounds passed through from __sanitizer_before_thread_create_hook
381f9cb04fSpatrick // or InitializeMainThread.
391f9cb04fSpatrick auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
401f9cb04fSpatrick stack_begin_ = args->stack_begin;
411f9cb04fSpatrick stack_end_ = args->stack_end;
421f9cb04fSpatrick }
431f9cb04fSpatrick
441f9cb04fSpatrick struct OnStartedArgs {
451f9cb04fSpatrick uptr cache_begin, cache_end;
461f9cb04fSpatrick };
471f9cb04fSpatrick
OnStarted(void * arg)481f9cb04fSpatrick void ThreadContext::OnStarted(void *arg) {
491f9cb04fSpatrick auto args = reinterpret_cast<const OnStartedArgs *>(arg);
501f9cb04fSpatrick cache_begin_ = args->cache_begin;
511f9cb04fSpatrick cache_end_ = args->cache_end;
521f9cb04fSpatrick }
531f9cb04fSpatrick
ThreadStart(u32 tid)541f9cb04fSpatrick void ThreadStart(u32 tid) {
551f9cb04fSpatrick OnStartedArgs args;
561f9cb04fSpatrick GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
571f9cb04fSpatrick CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
581f9cb04fSpatrick ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
591f9cb04fSpatrick }
601f9cb04fSpatrick
InitializeMainThread()611f9cb04fSpatrick void InitializeMainThread() {
621f9cb04fSpatrick OnCreatedArgs args;
631f9cb04fSpatrick __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
641f9cb04fSpatrick &args.stack_begin);
65*810390e3Srobert u32 tid = ThreadCreate(kMainTid, true, &args);
661f9cb04fSpatrick CHECK_EQ(tid, 0);
671f9cb04fSpatrick ThreadStart(tid);
681f9cb04fSpatrick }
691f9cb04fSpatrick
GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> * caches)701f9cb04fSpatrick void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
71*810390e3Srobert GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
721f9cb04fSpatrick [](ThreadContextBase *tctx, void *arg) {
731f9cb04fSpatrick auto ctx = static_cast<ThreadContext *>(tctx);
741f9cb04fSpatrick static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
751f9cb04fSpatrick },
761f9cb04fSpatrick caches);
771f9cb04fSpatrick }
781f9cb04fSpatrick
79*810390e3Srobert // On Fuchsia, leak detection is done by a special hook after atexit hooks.
80*810390e3Srobert // So this doesn't install any atexit hook like on other platforms.
InstallAtExitCheckLeaks()81*810390e3Srobert void InstallAtExitCheckLeaks() {}
82*810390e3Srobert
83*810390e3Srobert // ASan defines this to check its `halt_on_error` flag.
UseExitcodeOnLeak()84*810390e3Srobert bool UseExitcodeOnLeak() { return true; }
85*810390e3Srobert
861f9cb04fSpatrick } // namespace __lsan
871f9cb04fSpatrick
881f9cb04fSpatrick // These are declared (in extern "C") by <zircon/sanitizer.h>.
891f9cb04fSpatrick // The system runtime will call our definitions directly.
901f9cb04fSpatrick
911f9cb04fSpatrick // This is called before each thread creation is attempted. So, in
921f9cb04fSpatrick // its first call, the calling thread is the initial and sole thread.
__sanitizer_before_thread_create_hook(thrd_t thread,bool detached,const char * name,void * stack_base,size_t stack_size)931f9cb04fSpatrick void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
941f9cb04fSpatrick const char *name, void *stack_base,
951f9cb04fSpatrick size_t stack_size) {
961f9cb04fSpatrick ENSURE_LSAN_INITED;
971f9cb04fSpatrick EnsureMainThreadIDIsCorrect();
981f9cb04fSpatrick OnCreatedArgs args;
991f9cb04fSpatrick args.stack_begin = reinterpret_cast<uptr>(stack_base);
1001f9cb04fSpatrick args.stack_end = args.stack_begin + stack_size;
1011f9cb04fSpatrick u32 parent_tid = GetCurrentThread();
102*810390e3Srobert u32 tid = ThreadCreate(parent_tid, detached, &args);
1031f9cb04fSpatrick return reinterpret_cast<void *>(static_cast<uptr>(tid));
1041f9cb04fSpatrick }
1051f9cb04fSpatrick
1061f9cb04fSpatrick // This is called after creating a new thread (in the creating thread),
1071f9cb04fSpatrick // with the pointer returned by __sanitizer_before_thread_create_hook (above).
__sanitizer_thread_create_hook(void * hook,thrd_t thread,int error)1081f9cb04fSpatrick void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
1091f9cb04fSpatrick u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
1101f9cb04fSpatrick // On success, there is nothing to do here.
1111f9cb04fSpatrick if (error != thrd_success) {
1121f9cb04fSpatrick // Clean up the thread registry for the thread creation that didn't happen.
113*810390e3Srobert GetLsanThreadRegistryLocked()->FinishThread(tid);
1141f9cb04fSpatrick }
1151f9cb04fSpatrick }
1161f9cb04fSpatrick
1171f9cb04fSpatrick // This is called in the newly-created thread before it runs anything else,
1181f9cb04fSpatrick // with the pointer returned by __sanitizer_before_thread_create_hook (above).
__sanitizer_thread_start_hook(void * hook,thrd_t self)1191f9cb04fSpatrick void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
1201f9cb04fSpatrick u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
1211f9cb04fSpatrick ThreadStart(tid);
1221f9cb04fSpatrick }
1231f9cb04fSpatrick
1241f9cb04fSpatrick // Each thread runs this just before it exits,
1251f9cb04fSpatrick // with the pointer returned by BeforeThreadCreateHook (above).
1261f9cb04fSpatrick // All per-thread destructors have already been called.
__sanitizer_thread_exit_hook(void * hook,thrd_t self)1271f9cb04fSpatrick void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
1281f9cb04fSpatrick
1291f9cb04fSpatrick #endif // SANITIZER_FUCHSIA
130