lsan_common_fuchsia.cpp 6.2 KB

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