[compiler-rt] 90a10f0 - [lsan] Support LeakSanitizer runtime on Fuchsia

Petr Hosek via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 28 11:35:45 PST 2020


Author: Roland McGrath
Date: 2020-01-28T11:34:53-08:00
New Revision: 90a10f00ff838f6031e225f11b72a7e9240e288f

URL: https://github.com/llvm/llvm-project/commit/90a10f00ff838f6031e225f11b72a7e9240e288f
DIFF: https://github.com/llvm/llvm-project/commit/90a10f00ff838f6031e225f11b72a7e9240e288f.diff

LOG: [lsan] Support LeakSanitizer runtime on Fuchsia

Support LeakSanitizer runtime on Fuchsia.

Patch By: mcgrathr

Differential Revision: https://reviews.llvm.org/D72887

Added: 
    compiler-rt/lib/lsan/lsan_common_fuchsia.cpp
    compiler-rt/lib/lsan/lsan_fuchsia.cpp
    compiler-rt/lib/lsan/lsan_fuchsia.h
    compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp

Modified: 
    compiler-rt/cmake/config-ix.cmake
    compiler-rt/lib/asan/asan_thread.cpp
    compiler-rt/lib/lsan/CMakeLists.txt
    compiler-rt/lib/lsan/lsan.cpp
    compiler-rt/lib/lsan/lsan.h
    compiler-rt/lib/lsan/lsan_allocator.h
    compiler-rt/lib/lsan/lsan_common.cpp
    compiler-rt/lib/lsan/lsan_common.h
    compiler-rt/lib/lsan/lsan_interceptors.cpp
    compiler-rt/lib/lsan/lsan_linux.cpp
    compiler-rt/lib/lsan/lsan_posix.cpp
    compiler-rt/lib/sanitizer_common/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index d9e4b497d20f..6a9f7f3c84a5 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -640,7 +640,7 @@ else()
 endif()
 
 if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
-    OS_NAME MATCHES "Darwin|Linux|NetBSD")
+    OS_NAME MATCHES "Darwin|Linux|NetBSD|Fuchsia")
   set(COMPILER_RT_HAS_LSAN TRUE)
 else()
   set(COMPILER_RT_HAS_LSAN FALSE)

diff  --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 6734d9a1668c..f0df8bd4b374 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -480,6 +480,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
   return true;
 }
 
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
+
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
                             void *arg) {
   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);

diff  --git a/compiler-rt/lib/lsan/CMakeLists.txt b/compiler-rt/lib/lsan/CMakeLists.txt
index e0dcdcde4704..ff8d38d84849 100644
--- a/compiler-rt/lib/lsan/CMakeLists.txt
+++ b/compiler-rt/lib/lsan/CMakeLists.txt
@@ -5,6 +5,7 @@ append_rtti_flag(OFF LSAN_CFLAGS)
 
 set(LSAN_COMMON_SOURCES
   lsan_common.cpp
+  lsan_common_fuchsia.cpp
   lsan_common_linux.cpp
   lsan_common_mac.cpp
   )
@@ -12,6 +13,7 @@ set(LSAN_COMMON_SOURCES
 set(LSAN_SOURCES
   lsan.cpp
   lsan_allocator.cpp
+  lsan_fuchsia.cpp
   lsan_interceptors.cpp
   lsan_linux.cpp
   lsan_mac.cpp

diff  --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp
index 93a6f29beaad..80a6e2fa7016 100644
--- a/compiler-rt/lib/lsan/lsan.cpp
+++ b/compiler-rt/lib/lsan/lsan.cpp
@@ -15,7 +15,6 @@
 
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_flag_parser.h"
-#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "lsan_allocator.h"
 #include "lsan_common.h"
 #include "lsan_thread.h"
@@ -87,17 +86,6 @@ static void InitializeFlags() {
   __sanitizer_set_report_path(common_flags()->log_path);
 }
 
-static void OnStackUnwind(const SignalContext &sig, const void *,
-                          BufferedStackTrace *stack) {
-  stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
-                common_flags()->fast_unwind_on_fatal);
-}
-
-static void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
-  HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
-                     nullptr);
-}
-
 extern "C" void __lsan_init() {
   CHECK(!lsan_init_is_running);
   if (lsan_inited)

diff  --git a/compiler-rt/lib/lsan/lsan.h b/compiler-rt/lib/lsan/lsan.h
index 4cc8ef0c8ebc..1e82ad72f005 100644
--- a/compiler-rt/lib/lsan/lsan.h
+++ b/compiler-rt/lib/lsan/lsan.h
@@ -14,6 +14,8 @@
 #include "lsan_thread.h"
 #if SANITIZER_POSIX
 #include "lsan_posix.h"
+#elif SANITIZER_FUCHSIA
+#include "lsan_fuchsia.h"
 #endif
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
@@ -36,6 +38,7 @@ namespace __lsan {
 
 void InitializeInterceptors();
 void ReplaceSystemMalloc();
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
 
 #define ENSURE_LSAN_INITED do {   \
   CHECK(!lsan_init_is_running);   \

diff  --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h
index e13970997672..bda9d8cdf746 100644
--- a/compiler-rt/lib/lsan/lsan_allocator.h
+++ b/compiler-rt/lib/lsan/lsan_allocator.h
@@ -66,7 +66,10 @@ template <typename AddressSpaceView>
 using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
 using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
 #elif defined(__x86_64__) || defined(__powerpc64__)
-# if defined(__powerpc64__)
+# if SANITIZER_FUCHSIA
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
+# elif defined(__powerpc64__)
 const uptr kAllocatorSpace = 0xa0000000000ULL;
 const uptr kAllocatorSize  = 0x20000000000ULL;  // 2T.
 # else

diff  --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index aeaf0a39fde5..32ea4e880038 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -211,6 +211,13 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
   ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
 }
 
+#if SANITIZER_FUCHSIA
+
+// Fuchsia handles all threads together with its own callback.
+static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {}
+
+#else
+
 // Scans thread data (stacks and TLS) for heap pointers.
 static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
                            Frontier *frontier) {
@@ -308,6 +315,8 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
   }
 }
 
+#endif  // SANITIZER_FUCHSIA
+
 void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
                     uptr region_begin, uptr region_end, bool is_readable) {
   uptr intersection_begin = Max(root_region.begin, region_begin);
@@ -531,6 +540,14 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
   }
 }
 
+#if SANITIZER_FUCHSIA
+
+// Fuchsia provides a libc interface that guarantees all threads are
+// covered, and SuspendedThreadList is never really used.
+static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
+
+#else  // !SANITIZER_FUCHSIA
+
 static void ReportUnsuspendedThreads(
     const SuspendedThreadsList &suspended_threads) {
   InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
@@ -543,6 +560,8 @@ static void ReportUnsuspendedThreads(
       &ReportIfNotSuspended, &threads);
 }
 
+#endif  // !SANITIZER_FUCHSIA
+
 static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
                                   void *arg) {
   CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);

diff  --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index 41075d658456..6252d52c1978 100644
--- a/compiler-rt/lib/lsan/lsan_common.h
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -40,7 +40,7 @@
 #elif defined(__arm__) && \
     SANITIZER_LINUX && !SANITIZER_ANDROID
 #define CAN_SANITIZE_LEAKS 1
-#elif SANITIZER_NETBSD
+#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
 #define CAN_SANITIZE_LEAKS 1
 #else
 #define CAN_SANITIZE_LEAKS 0
@@ -223,6 +223,7 @@ ThreadRegistry *GetThreadRegistryLocked();
 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
                            uptr *cache_end, DTLS **dtls);
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
                             void *arg);
 // If called from the main thread, updates the main thread's TID in the thread

diff  --git a/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp b/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp
new file mode 100644
index 000000000000..caedbf155969
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp
@@ -0,0 +1,166 @@
+//=-- lsan_common_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.
+// Implementation of common leak checking functionality. Fuchsia-specific code.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
+#include <zircon/sanitizer.h>
+
+#include "lsan_allocator.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+// Ensure that the Zircon system ABI is linked in.
+#pragma comment(lib, "zircon")
+
+namespace __lsan {
+
+void InitializePlatformSpecificModules() {}
+
+LoadedModule *GetLinker() { return nullptr; }
+
+__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+  if (disable_counter == 0) {
+    DisableCounterUnderflow();
+  }
+  disable_counter--;
+}
+
+// There is nothing left to do after the globals callbacks.
+void ProcessGlobalRegions(Frontier *frontier) {}
+
+// Nothing to do here.
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
+
+// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit
+// code if required at that point.  Calling Die() here is undefined
+// behavior and causes rare race conditions.
+void HandleLeaks() {}
+
+int ExitHook(int status) {
+  return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
+}
+
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam *argument) {
+  LockThreadRegistry();
+  LockAllocator();
+
+  struct Params {
+    InternalMmapVector<uptr> allocator_caches;
+    StopTheWorldCallback callback;
+    CheckForLeaksParam *argument;
+  } params = {{}, callback, argument};
+
+  // Callback from libc for globals (data/bss modulo relro), when enabled.
+  auto globals = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanGlobalRange(begin, end, &params->argument->frontier);
+  };
+
+  // Callback from libc for thread stacks.
+  auto stacks = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanRangeForPointers(begin, end, &params->argument->frontier, "STACK",
+                         kReachable);
+  };
+
+  // Callback from libc for thread registers.
+  auto registers = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanRangeForPointers(begin, end, &params->argument->frontier, "REGISTERS",
+                         kReachable);
+  };
+
+  if (flags()->use_tls) {
+    // Collect the allocator cache range from each thread so these
+    // can all be excluded from the reported TLS ranges.
+    GetAllThreadAllocatorCachesLocked(&params.allocator_caches);
+    __sanitizer::Sort(params.allocator_caches.data(),
+                      params.allocator_caches.size());
+  }
+
+  // Callback from libc for TLS regions.  This includes thread_local
+  // variables as well as C11 tss_set and POSIX pthread_setspecific.
+  auto tls = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
+                                             params->allocator_caches.size(),
+                                             begin, CompareLess<uptr>());
+    if (i < params->allocator_caches.size() &&
+        params->allocator_caches[i] >= begin &&
+        end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
+      // Split the range in two and omit the allocator cache within.
+      ScanRangeForPointers(begin, params->allocator_caches[i],
+                           &params->argument->frontier, "TLS", kReachable);
+      uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
+      ScanRangeForPointers(begin2, end, &params->argument->frontier, "TLS",
+                           kReachable);
+    } else {
+      ScanRangeForPointers(begin, end, &params->argument->frontier, "TLS",
+                           kReachable);
+    }
+  };
+
+  // This stops the world and then makes callbacks for various memory regions.
+  // The final callback is the last thing before the world starts up again.
+  __sanitizer_memory_snapshot(
+      flags()->use_globals ? globals : nullptr,
+      flags()->use_stacks ? stacks : nullptr,
+      flags()->use_registers ? registers : nullptr,
+      flags()->use_tls ? tls : nullptr,
+      [](zx_status_t, void *data) {
+        auto params = static_cast<const Params *>(data);
+
+        // We don't use the thread registry at all for enumerating the threads
+        // and their stacks, registers, and TLS regions.  So use it separately
+        // just for the allocator cache, and to call ForEachExtraStackRange,
+        // which ASan needs.
+        if (flags()->use_stacks) {
+          GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+              [](ThreadContextBase *tctx, void *arg) {
+                ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb,
+                                       arg);
+              },
+              &params->argument->frontier);
+        }
+
+        params->callback({}, params->argument);
+      },
+      &params);
+
+  UnlockAllocator();
+  UnlockThreadRegistry();
+}
+
+}  // namespace __lsan
+
+// This is declared (in extern "C") by <zircon/sanitizer.h>.
+// _Exit calls this directly to intercept and change the status value.
+int __sanitizer_process_exit_hook(int status) {
+  return __lsan::ExitHook(status);
+}
+
+#endif

diff  --git a/compiler-rt/lib/lsan/lsan_fuchsia.cpp b/compiler-rt/lib/lsan/lsan_fuchsia.cpp
new file mode 100644
index 000000000000..40e65c6fb729
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_fuchsia.cpp
@@ -0,0 +1,123 @@
+//=-- 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 <zircon/sanitizer.h>
+
+#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<const OnCreatedArgs *>(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<const OnStartedArgs *>(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<uptr> *caches) {
+  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *tctx, void *arg) {
+        auto ctx = static_cast<ThreadContext *>(tctx);
+        static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
+      },
+      caches);
+}
+
+}  // namespace __lsan
+
+// These are declared (in extern "C") by <zircon/sanitizer.h>.
+// 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<uptr>(thread);
+  ENSURE_LSAN_INITED;
+  EnsureMainThreadIDIsCorrect();
+  OnCreatedArgs args;
+  args.stack_begin = reinterpret_cast<uptr>(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<void *>(static_cast<uptr>(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<u32>(reinterpret_cast<uptr>(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<u32>(reinterpret_cast<uptr>(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

diff  --git a/compiler-rt/lib/lsan/lsan_fuchsia.h b/compiler-rt/lib/lsan/lsan_fuchsia.h
new file mode 100644
index 000000000000..65d20ea21148
--- /dev/null
+++ b/compiler-rt/lib/lsan/lsan_fuchsia.h
@@ -0,0 +1,35 @@
+//=-- lsan_fuchsia.h ---------------------------------------------------===//
+//
+// 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.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LSAN_FUCHSIA_H
+#define LSAN_FUCHSIA_H
+
+#include "lsan_thread.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if !SANITIZER_FUCHSIA
+#error "lsan_fuchsia.h is used only on Fuchsia systems (SANITIZER_FUCHSIA)"
+#endif
+
+namespace __lsan {
+
+class ThreadContext : public ThreadContextLsanBase {
+ public:
+  explicit ThreadContext(int tid);
+  void OnCreated(void *arg) override;
+  void OnStarted(void *arg) override;
+};
+
+}  // namespace __lsan
+
+#endif  // LSAN_FUCHSIA_H

diff  --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp
index 0ec84ff15825..9ce9b78c5a5f 100644
--- a/compiler-rt/lib/lsan/lsan_interceptors.cpp
+++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp
@@ -63,6 +63,9 @@ INTERCEPTOR(void, free, void *p) {
 }
 
 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+  // This hack is not required for Fuchsia because there are no dlsym calls
+  // involved in setting up interceptors.
+#if !SANITIZER_FUCHSIA
   if (lsan_init_is_running) {
     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
     const uptr kCallocPoolSize = 1024;
@@ -74,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
     CHECK(allocated < kCallocPoolSize);
     return mem;
   }
+#endif  // !SANITIZER_FUCHSIA
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
   return lsan_calloc(nmemb, size, stack);
@@ -102,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) {
   GET_STACK_TRACE_MALLOC;
   return lsan_valloc(size, stack);
 }
-#endif
+#endif  // !SANITIZER_MAC
 
 #if SANITIZER_INTERCEPT_MEMALIGN
 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
@@ -309,7 +313,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
 
 ///// Thread initialization and finalization. /////
 
-#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
+#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
 static unsigned g_thread_finalize_key;
 
 static void thread_finalize(void *v) {
@@ -396,6 +400,8 @@ INTERCEPTOR(char *, strerror, int errnum) {
 #define LSAN_MAYBE_INTERCEPT_STRERROR
 #endif
 
+#if SANITIZER_POSIX
+
 struct ThreadParam {
   void *(*callback)(void *arg);
   void *param;
@@ -478,9 +484,13 @@ INTERCEPTOR(void, _exit, int status) {
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
+#endif  // SANITIZER_POSIX
+
 namespace __lsan {
 
 void InitializeInterceptors() {
+  // Fuchsia doesn't use interceptors that require any setup.
+#if !SANITIZER_FUCHSIA
   InitializeSignalInterceptors();
 
   INTERCEPT_FUNCTION(malloc);
@@ -516,6 +526,8 @@ void InitializeInterceptors() {
     Die();
   }
 #endif
+
+#endif  // !SANITIZER_FUCHSIA
 }
 
 } // namespace __lsan

diff  --git a/compiler-rt/lib/lsan/lsan_linux.cpp b/compiler-rt/lib/lsan/lsan_linux.cpp
index 14a42b75d2af..47c2f21b5a6b 100644
--- a/compiler-rt/lib/lsan/lsan_linux.cpp
+++ b/compiler-rt/lib/lsan/lsan_linux.cpp
@@ -6,13 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is a part of LeakSanitizer. Linux/NetBSD-specific code.
+// This file is a part of LeakSanitizer. Linux/NetBSD/Fuchsia-specific code.
 //
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common/sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_NETBSD
+#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
 
 #include "lsan_allocator.h"
 
@@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
 
 } // namespace __lsan
 
-#endif  // SANITIZER_LINUX || SANITIZER_NETBSD
+#endif  // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA

diff  --git a/compiler-rt/lib/lsan/lsan_posix.cpp b/compiler-rt/lib/lsan/lsan_posix.cpp
index 5742c572f316..8e05915dd1b9 100644
--- a/compiler-rt/lib/lsan/lsan_posix.cpp
+++ b/compiler-rt/lib/lsan/lsan_posix.cpp
@@ -80,6 +80,17 @@ void InitializeMainThread() {
   ThreadStart(tid, GetTid());
 }
 
+static void OnStackUnwind(const SignalContext &sig, const void *,
+                          BufferedStackTrace *stack) {
+  stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
+                common_flags()->fast_unwind_on_fatal);
+}
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+  HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
+                     nullptr);
+}
+
 }  // namespace __lsan
 
 #endif  // SANITIZER_POSIX

diff  --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 6ba2c5e0637a..235c5d78238b 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -35,6 +35,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
   sanitizer_procmaps_solaris.cpp
   sanitizer_rtems.cpp
   sanitizer_solaris.cpp
+  sanitizer_stoptheworld_fuchsia.cpp
   sanitizer_stoptheworld_mac.cpp
   sanitizer_suppressions.cpp
   sanitizer_tls_get_addr.cpp

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
new file mode 100644
index 000000000000..3a246443ed99
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
@@ -0,0 +1,42 @@
+//===-- sanitizer_stoptheworld_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
+//
+//===---------------------------------------------------------------------===//
+//
+// See sanitizer_stoptheworld.h for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FUCHSIA
+
+#include <zircon/sanitizer.h>
+
+#include "sanitizer_stoptheworld.h"
+
+namespace __sanitizer {
+
+// The Fuchsia implementation stops the world but doesn't offer a real
+// SuspendedThreadsList argument.  This is enough for ASan's use case,
+// and LSan does not use this API on Fuchsia.
+void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+  struct Params {
+    StopTheWorldCallback callback;
+    void *argument;
+  } params = {callback, argument};
+  __sanitizer_memory_snapshot(
+      nullptr, nullptr, nullptr, nullptr,
+      [](zx_status_t, void *data) {
+        auto params = reinterpret_cast<Params *>(data);
+        params->callback({}, params->argument);
+      },
+      &params);
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FUCHSIA


        


More information about the llvm-commits mailing list