lsan_common_fuchsia.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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-exception
  6. //
  7. //===---------------------------------------------------------------------===//
  8. //
  9. // This file is a part of LeakSanitizer.
  10. // Implementation of common leak checking functionality. Fuchsia-specific code.
  11. //
  12. //===---------------------------------------------------------------------===//
  13. #include "lsan_common.h"
  14. #include "sanitizer_common/sanitizer_platform.h"
  15. #if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
  16. #error #include <zircon/sanitizer.h>
  17. #include "lsan_allocator.h"
  18. #include "sanitizer_common/sanitizer_flags.h"
  19. #include "sanitizer_common/sanitizer_stoptheworld_fuchsia.h"
  20. #include "sanitizer_common/sanitizer_thread_registry.h"
  21. // Ensure that the Zircon system ABI is linked in.
  22. #pragma comment(lib, "zircon")
  23. namespace __lsan {
  24. void InitializePlatformSpecificModules() {}
  25. LoadedModule *GetLinker() { return nullptr; }
  26. __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
  27. bool DisabledInThisThread() { return disable_counter > 0; }
  28. void DisableInThisThread() { disable_counter++; }
  29. void EnableInThisThread() {
  30. if (disable_counter == 0) {
  31. DisableCounterUnderflow();
  32. }
  33. disable_counter--;
  34. }
  35. // There is nothing left to do after the globals callbacks.
  36. void ProcessGlobalRegions(Frontier *frontier) {}
  37. // Nothing to do here.
  38. void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
  39. // On Fuchsia, we can intercept _Exit gracefully, and return a failing exit
  40. // code if required at that point. Calling Die() here is undefined
  41. // behavior and causes rare race conditions.
  42. void HandleLeaks() {}
  43. int ExitHook(int status) {
  44. return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
  45. }
  46. void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
  47. CheckForLeaksParam *argument) {
  48. ScopedStopTheWorldLock lock;
  49. struct Params {
  50. InternalMmapVector<uptr> allocator_caches;
  51. StopTheWorldCallback callback;
  52. CheckForLeaksParam *argument;
  53. } params = {{}, callback, argument};
  54. // Callback from libc for globals (data/bss modulo relro), when enabled.
  55. auto globals = +[](void *chunk, size_t size, void *data) {
  56. auto params = static_cast<const Params *>(data);
  57. uptr begin = reinterpret_cast<uptr>(chunk);
  58. uptr end = begin + size;
  59. ScanGlobalRange(begin, end, &params->argument->frontier);
  60. };
  61. // Callback from libc for thread stacks.
  62. auto stacks = +[](void *chunk, size_t size, void *data) {
  63. auto params = static_cast<const Params *>(data);
  64. uptr begin = reinterpret_cast<uptr>(chunk);
  65. uptr end = begin + size;
  66. ScanRangeForPointers(begin, end, &params->argument->frontier, "STACK",
  67. kReachable);
  68. };
  69. // Callback from libc for thread registers.
  70. auto registers = +[](void *chunk, size_t size, void *data) {
  71. auto params = static_cast<const Params *>(data);
  72. uptr begin = reinterpret_cast<uptr>(chunk);
  73. uptr end = begin + size;
  74. ScanRangeForPointers(begin, end, &params->argument->frontier, "REGISTERS",
  75. kReachable);
  76. };
  77. if (flags()->use_tls) {
  78. // Collect the allocator cache range from each thread so these
  79. // can all be excluded from the reported TLS ranges.
  80. GetAllThreadAllocatorCachesLocked(&params.allocator_caches);
  81. __sanitizer::Sort(params.allocator_caches.data(),
  82. params.allocator_caches.size());
  83. }
  84. // Callback from libc for TLS regions. This includes thread_local
  85. // variables as well as C11 tss_set and POSIX pthread_setspecific.
  86. auto tls = +[](void *chunk, size_t size, void *data) {
  87. auto params = static_cast<const Params *>(data);
  88. uptr begin = reinterpret_cast<uptr>(chunk);
  89. uptr end = begin + size;
  90. auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
  91. if (i < params->allocator_caches.size() &&
  92. params->allocator_caches[i] >= begin &&
  93. end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
  94. // Split the range in two and omit the allocator cache within.
  95. ScanRangeForPointers(begin, params->allocator_caches[i],
  96. &params->argument->frontier, "TLS", kReachable);
  97. uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
  98. ScanRangeForPointers(begin2, end, &params->argument->frontier, "TLS",
  99. kReachable);
  100. } else {
  101. ScanRangeForPointers(begin, end, &params->argument->frontier, "TLS",
  102. kReachable);
  103. }
  104. };
  105. // This stops the world and then makes callbacks for various memory regions.
  106. // The final callback is the last thing before the world starts up again.
  107. __sanitizer_memory_snapshot(
  108. flags()->use_globals ? globals : nullptr,
  109. flags()->use_stacks ? stacks : nullptr,
  110. flags()->use_registers ? registers : nullptr,
  111. flags()->use_tls ? tls : nullptr,
  112. [](zx_status_t, void *data) {
  113. auto params = static_cast<const Params *>(data);
  114. // We don't use the thread registry at all for enumerating the threads
  115. // and their stacks, registers, and TLS regions. So use it separately
  116. // just for the allocator cache, and to call ForEachExtraStackRange,
  117. // which ASan needs.
  118. if (flags()->use_stacks) {
  119. GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
  120. [](ThreadContextBase *tctx, void *arg) {
  121. ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb,
  122. arg);
  123. },
  124. &params->argument->frontier);
  125. }
  126. params->callback(SuspendedThreadsListFuchsia(), params->argument);
  127. },
  128. &params);
  129. }
  130. } // namespace __lsan
  131. // This is declared (in extern "C") by <zircon/sanitizer.h>.
  132. // _Exit calls this directly to intercept and change the status value.
  133. int __sanitizer_process_exit_hook(int status) {
  134. return __lsan::ExitHook(status);
  135. }
  136. #endif