brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · cb3fe1f Raw
169 lines · cpp
1//=-- lsan_common_fuchsia.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===---------------------------------------------------------------------===//8//9// This file is a part of LeakSanitizer.10// Implementation of common leak checking functionality. Fuchsia-specific code.11//12//===---------------------------------------------------------------------===//13 14#include "lsan_common.h"15#include "lsan_thread.h"16#include "sanitizer_common/sanitizer_platform.h"17 18#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA19#include <zircon/sanitizer.h>20 21#include "lsan_allocator.h"22#include "sanitizer_common/sanitizer_flags.h"23#include "sanitizer_common/sanitizer_stoptheworld_fuchsia.h"24#include "sanitizer_common/sanitizer_thread_registry.h"25 26// Ensure that the Zircon system ABI is linked in.27#pragma comment(lib, "zircon")28 29namespace __lsan {30 31void InitializePlatformSpecificModules() {}32 33LoadedModule *GetLinker() { return nullptr; }34 35__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;36bool DisabledInThisThread() { return disable_counter > 0; }37void DisableInThisThread() { disable_counter++; }38void EnableInThisThread() {39  if (disable_counter == 0) {40    DisableCounterUnderflow();41  }42  disable_counter--;43}44 45// There is nothing left to do after the globals callbacks.46void ProcessGlobalRegions(Frontier *frontier) {}47 48// Nothing to do here.49void ProcessPlatformSpecificAllocations(Frontier *frontier) {}50 51// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit52// code if required at that point.  Calling Die() here is undefined53// behavior and causes rare race conditions.54void HandleLeaks() {}55 56// This is defined differently in asan_fuchsia.cpp and lsan_fuchsia.cpp.57bool UseExitcodeOnLeak();58 59int ExitHook(int status) {60  if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {61    if (UseExitcodeOnLeak())62      DoLeakCheck();63    else64      DoRecoverableLeakCheckVoid();65  }66  return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;67}68 69void LockStuffAndStopTheWorld(StopTheWorldCallback callback,70                              CheckForLeaksParam *argument) {71  ScopedStopTheWorldLock lock;72 73  struct Params {74    InternalMmapVector<uptr> allocator_caches;75    StopTheWorldCallback callback;76    CheckForLeaksParam *argument;77  } params = {{}, callback, argument};78 79  // Callback from libc for globals (data/bss modulo relro), when enabled.80  auto globals = +[](void *chunk, size_t size, void *data) {81    auto params = static_cast<const Params *>(data);82    uptr begin = reinterpret_cast<uptr>(chunk);83    uptr end = begin + size;84    ScanGlobalRange(begin, end, &params->argument->frontier);85  };86 87  // Callback from libc for thread stacks.88  auto stacks = +[](void *chunk, size_t size, void *data) {89    auto params = static_cast<const Params *>(data);90    uptr begin = reinterpret_cast<uptr>(chunk);91    uptr end = begin + size;92    ScanRangeForPointers(begin, end, &params->argument->frontier, "STACK",93                         kReachable);94  };95 96  // Callback from libc for thread registers.97  auto registers = +[](void *chunk, size_t size, void *data) {98    auto params = static_cast<const Params *>(data);99    uptr begin = reinterpret_cast<uptr>(chunk);100    uptr end = begin + size;101    ScanRangeForPointers(begin, end, &params->argument->frontier, "REGISTERS",102                         kReachable);103  };104 105  if (flags()->use_tls) {106    // Collect the allocator cache range from each thread so these107    // can all be excluded from the reported TLS ranges.108    GetAllThreadAllocatorCachesLocked(&params.allocator_caches);109    __sanitizer::Sort(params.allocator_caches.data(),110                      params.allocator_caches.size());111  }112 113  // Callback from libc for TLS regions.  This includes thread_local114  // variables as well as C11 tss_set and POSIX pthread_setspecific.115  auto tls = +[](void *chunk, size_t size, void *data) {116    auto params = static_cast<const Params *>(data);117    uptr begin = reinterpret_cast<uptr>(chunk);118    uptr end = begin + size;119    auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);120    if (i < params->allocator_caches.size() &&121        params->allocator_caches[i] >= begin &&122        params->allocator_caches[i] <= end &&123        end - params->allocator_caches[i] >= sizeof(AllocatorCache)) {124      // Split the range in two and omit the allocator cache within.125      ScanRangeForPointers(begin, params->allocator_caches[i],126                           &params->argument->frontier, "TLS", kReachable);127      uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);128      ScanRangeForPointers(begin2, end, &params->argument->frontier, "TLS",129                           kReachable);130    } else {131      ScanRangeForPointers(begin, end, &params->argument->frontier, "TLS",132                           kReachable);133    }134  };135 136  // This stops the world and then makes callbacks for various memory regions.137  // The final callback is the last thing before the world starts up again.138  __sanitizer_memory_snapshot(139      flags()->use_globals ? globals : nullptr,140      flags()->use_stacks ? stacks : nullptr,141      flags()->use_registers ? registers : nullptr,142      flags()->use_tls ? tls : nullptr,143      [](zx_status_t, void *data) {144        auto params = static_cast<const Params *>(data);145 146        // We don't use the thread registry at all for enumerating the threads147        // and their stacks, registers, and TLS regions.  So use it separately148        // just for the allocator cache, and to call ScanExtraStackRanges,149        // which ASan needs.150        if (flags()->use_stacks) {151          InternalMmapVector<Range> ranges;152          GetThreadExtraStackRangesLocked(&ranges);153          ScanExtraStackRanges(ranges, &params->argument->frontier);154        }155        params->callback(SuspendedThreadsListFuchsia(), params->argument);156      },157      &params);158}159 160}  // namespace __lsan161 162// This is declared (in extern "C") by <zircon/sanitizer.h>.163// _Exit calls this directly to intercept and change the status value.164int __sanitizer_process_exit_hook(int status) {165  return __lsan::ExitHook(status);166}167 168#endif169