xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/lsan/lsan_fuchsia.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //=-- lsan_fuchsia.cpp ---------------------------------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===---------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This file is a part of LeakSanitizer.
105ffd83dbSDimitry Andric // Standalone LSan RTL code specific to Fuchsia.
115ffd83dbSDimitry Andric //
125ffd83dbSDimitry Andric //===---------------------------------------------------------------------===//
135ffd83dbSDimitry Andric 
145ffd83dbSDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
155ffd83dbSDimitry Andric 
165ffd83dbSDimitry Andric #if SANITIZER_FUCHSIA
175ffd83dbSDimitry Andric #include <zircon/sanitizer.h>
185ffd83dbSDimitry Andric 
195ffd83dbSDimitry Andric #include "lsan.h"
205ffd83dbSDimitry Andric #include "lsan_allocator.h"
215ffd83dbSDimitry Andric 
225ffd83dbSDimitry Andric using namespace __lsan;
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric namespace __lsan {
255ffd83dbSDimitry Andric 
LsanOnDeadlySignal(int signo,void * siginfo,void * context)265ffd83dbSDimitry Andric void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
275ffd83dbSDimitry Andric 
ThreadContext(int tid)285ffd83dbSDimitry Andric ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric struct OnCreatedArgs {
315ffd83dbSDimitry Andric   uptr stack_begin, stack_end;
325ffd83dbSDimitry Andric };
335ffd83dbSDimitry Andric 
345ffd83dbSDimitry Andric // On Fuchsia, the stack bounds of a new thread are available before
355ffd83dbSDimitry Andric // the thread itself has started running.
OnCreated(void * arg)365ffd83dbSDimitry Andric void ThreadContext::OnCreated(void *arg) {
375ffd83dbSDimitry Andric   // Stack bounds passed through from __sanitizer_before_thread_create_hook
385ffd83dbSDimitry Andric   // or InitializeMainThread.
395ffd83dbSDimitry Andric   auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
405ffd83dbSDimitry Andric   stack_begin_ = args->stack_begin;
415ffd83dbSDimitry Andric   stack_end_ = args->stack_end;
425ffd83dbSDimitry Andric }
435ffd83dbSDimitry Andric 
445ffd83dbSDimitry Andric struct OnStartedArgs {
455ffd83dbSDimitry Andric   uptr cache_begin, cache_end;
465ffd83dbSDimitry Andric };
475ffd83dbSDimitry Andric 
OnStarted(void * arg)485ffd83dbSDimitry Andric void ThreadContext::OnStarted(void *arg) {
4906c3fb27SDimitry Andric   ThreadContextLsanBase::OnStarted(arg);
505ffd83dbSDimitry Andric   auto args = reinterpret_cast<const OnStartedArgs *>(arg);
515ffd83dbSDimitry Andric   cache_begin_ = args->cache_begin;
525ffd83dbSDimitry Andric   cache_end_ = args->cache_end;
535ffd83dbSDimitry Andric }
545ffd83dbSDimitry Andric 
ThreadStart(u32 tid)555ffd83dbSDimitry Andric void ThreadStart(u32 tid) {
565ffd83dbSDimitry Andric   OnStartedArgs args;
575ffd83dbSDimitry Andric   GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
585ffd83dbSDimitry Andric   CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
595ffd83dbSDimitry Andric   ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
605ffd83dbSDimitry Andric }
615ffd83dbSDimitry Andric 
InitializeMainThread()625ffd83dbSDimitry Andric void InitializeMainThread() {
635ffd83dbSDimitry Andric   OnCreatedArgs args;
645ffd83dbSDimitry Andric   __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
655ffd83dbSDimitry Andric                                           &args.stack_begin);
66349cc55cSDimitry Andric   u32 tid = ThreadCreate(kMainTid, true, &args);
675ffd83dbSDimitry Andric   CHECK_EQ(tid, 0);
685ffd83dbSDimitry Andric   ThreadStart(tid);
695ffd83dbSDimitry Andric }
705ffd83dbSDimitry Andric 
GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> * caches)715ffd83dbSDimitry Andric void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
72bdd1243dSDimitry Andric   GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
735ffd83dbSDimitry Andric       [](ThreadContextBase *tctx, void *arg) {
745ffd83dbSDimitry Andric         auto ctx = static_cast<ThreadContext *>(tctx);
755ffd83dbSDimitry Andric         static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
765ffd83dbSDimitry Andric       },
775ffd83dbSDimitry Andric       caches);
785ffd83dbSDimitry Andric }
795ffd83dbSDimitry Andric 
8081ad6265SDimitry Andric // On Fuchsia, leak detection is done by a special hook after atexit hooks.
8181ad6265SDimitry Andric // So this doesn't install any atexit hook like on other platforms.
InstallAtExitCheckLeaks()8281ad6265SDimitry Andric void InstallAtExitCheckLeaks() {}
InstallAtForkHandler()83*5f757f3fSDimitry Andric void InstallAtForkHandler() {}
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric // ASan defines this to check its `halt_on_error` flag.
UseExitcodeOnLeak()8681ad6265SDimitry Andric bool UseExitcodeOnLeak() { return true; }
8781ad6265SDimitry Andric 
885ffd83dbSDimitry Andric }  // namespace __lsan
895ffd83dbSDimitry Andric 
905ffd83dbSDimitry Andric // These are declared (in extern "C") by <zircon/sanitizer.h>.
915ffd83dbSDimitry Andric // The system runtime will call our definitions directly.
925ffd83dbSDimitry Andric 
935ffd83dbSDimitry Andric // This is called before each thread creation is attempted.  So, in
945ffd83dbSDimitry Andric // 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)955ffd83dbSDimitry Andric void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
965ffd83dbSDimitry Andric                                             const char *name, void *stack_base,
975ffd83dbSDimitry Andric                                             size_t stack_size) {
985ffd83dbSDimitry Andric   ENSURE_LSAN_INITED;
995ffd83dbSDimitry Andric   EnsureMainThreadIDIsCorrect();
1005ffd83dbSDimitry Andric   OnCreatedArgs args;
1015ffd83dbSDimitry Andric   args.stack_begin = reinterpret_cast<uptr>(stack_base);
1025ffd83dbSDimitry Andric   args.stack_end = args.stack_begin + stack_size;
10306c3fb27SDimitry Andric   u32 parent_tid = GetCurrentThreadId();
104349cc55cSDimitry Andric   u32 tid = ThreadCreate(parent_tid, detached, &args);
1055ffd83dbSDimitry Andric   return reinterpret_cast<void *>(static_cast<uptr>(tid));
1065ffd83dbSDimitry Andric }
1075ffd83dbSDimitry Andric 
1085ffd83dbSDimitry Andric // This is called after creating a new thread (in the creating thread),
1095ffd83dbSDimitry Andric // with the pointer returned by __sanitizer_before_thread_create_hook (above).
__sanitizer_thread_create_hook(void * hook,thrd_t thread,int error)1105ffd83dbSDimitry Andric void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
1115ffd83dbSDimitry Andric   u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
1125ffd83dbSDimitry Andric   // On success, there is nothing to do here.
1135ffd83dbSDimitry Andric   if (error != thrd_success) {
1145ffd83dbSDimitry Andric     // Clean up the thread registry for the thread creation that didn't happen.
115bdd1243dSDimitry Andric     GetLsanThreadRegistryLocked()->FinishThread(tid);
1165ffd83dbSDimitry Andric   }
1175ffd83dbSDimitry Andric }
1185ffd83dbSDimitry Andric 
1195ffd83dbSDimitry Andric // This is called in the newly-created thread before it runs anything else,
1205ffd83dbSDimitry Andric // with the pointer returned by __sanitizer_before_thread_create_hook (above).
__sanitizer_thread_start_hook(void * hook,thrd_t self)1215ffd83dbSDimitry Andric void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
1225ffd83dbSDimitry Andric   u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
1235ffd83dbSDimitry Andric   ThreadStart(tid);
1245ffd83dbSDimitry Andric }
1255ffd83dbSDimitry Andric 
1265ffd83dbSDimitry Andric // Each thread runs this just before it exits,
1275ffd83dbSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
1285ffd83dbSDimitry Andric // All per-thread destructors have already been called.
__sanitizer_thread_exit_hook(void * hook,thrd_t self)1295ffd83dbSDimitry Andric void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
1305ffd83dbSDimitry Andric 
1315ffd83dbSDimitry Andric #endif  // SANITIZER_FUCHSIA
132