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