sanitizers.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #pragma once
  2. #include "defaults.h"
  3. extern "C" { // sanitizers API
  4. #if defined(_asan_enabled_) || defined(_lsan_enabled_)
  5. void __lsan_ignore_object(const void* p);
  6. #endif
  7. #if defined(_asan_enabled_)
  8. void __sanitizer_start_switch_fiber(void** fake_stack_save, const void* bottom, size_t size);
  9. void __sanitizer_finish_switch_fiber(void* fake_stack_save, const void** old_bottom, size_t* old_size);
  10. #endif
  11. #if defined(_msan_enabled_)
  12. void __msan_unpoison(const volatile void* a, size_t size);
  13. void __msan_poison(const volatile void* a, size_t size);
  14. void __msan_check_mem_is_initialized(const volatile void* x, size_t size);
  15. #endif
  16. #if defined(_tsan_enabled_)
  17. void __tsan_acquire(void* a);
  18. void __tsan_release(void* a);
  19. void* __tsan_get_current_fiber(void);
  20. void __tsan_destroy_fiber(void* fiber);
  21. void __tsan_switch_to_fiber(void* fiber, unsigned flags);
  22. #endif
  23. } // sanitizers API
  24. namespace NSan {
  25. class TFiberContext {
  26. public:
  27. TFiberContext() noexcept;
  28. TFiberContext(const void* stack, size_t len, const char* contName) noexcept;
  29. ~TFiberContext() noexcept {
  30. if (!IsMainFiber_) {
  31. #if defined(_asan_enabled_)
  32. if (Token_) {
  33. // destroy saved FakeStack
  34. void* activeFakeStack = nullptr;
  35. const void* activeStack = nullptr;
  36. size_t activeStackSize = 0;
  37. __sanitizer_start_switch_fiber(&activeFakeStack, (char*)Stack_, Len_);
  38. __sanitizer_finish_switch_fiber(Token_, &activeStack, &activeStackSize);
  39. __sanitizer_start_switch_fiber(nullptr, activeStack, activeStackSize);
  40. __sanitizer_finish_switch_fiber(activeFakeStack, nullptr, nullptr);
  41. }
  42. #endif
  43. #if defined(_tsan_enabled_)
  44. __tsan_destroy_fiber(CurrentTSanFiberContext_);
  45. #endif
  46. }
  47. }
  48. Y_FORCE_INLINE void BeforeSwitch(TFiberContext* old) noexcept {
  49. #if defined(_asan_enabled_)
  50. __sanitizer_start_switch_fiber(old ? &old->Token_ : nullptr, (char*)Stack_, Len_);
  51. #else
  52. (void)old;
  53. #endif
  54. #if defined(_tsan_enabled_)
  55. __tsan_switch_to_fiber(CurrentTSanFiberContext_, /*flags =*/0);
  56. #endif
  57. }
  58. void AfterSwitch() noexcept {
  59. #if defined(_asan_enabled_)
  60. __sanitizer_finish_switch_fiber(Token_, nullptr, nullptr);
  61. #endif
  62. }
  63. private:
  64. void* Token_;
  65. const void* Stack_;
  66. size_t Len_;
  67. const bool IsMainFiber_;
  68. #if defined(_tsan_enabled_)
  69. void* const CurrentTSanFiberContext_;
  70. #endif
  71. };
  72. // Returns plain if no sanitizer enabled or sanitized otherwise
  73. // Ment to be used in test code for constants (timeouts, etc)
  74. template <typename T>
  75. inline constexpr static T PlainOrUnderSanitizer(T plain, T sanitized) noexcept {
  76. #if defined(_tsan_enabled_) || defined(_msan_enabled_) || defined(_asan_enabled_)
  77. Y_UNUSED(plain);
  78. return sanitized;
  79. #else
  80. Y_UNUSED(sanitized);
  81. return plain;
  82. #endif
  83. }
  84. // Determines if asan present
  85. inline constexpr static bool ASanIsOn() noexcept {
  86. #if defined(_asan_enabled_)
  87. return true;
  88. #else
  89. return false;
  90. #endif
  91. }
  92. // Determines if tsan present
  93. inline constexpr static bool TSanIsOn() noexcept {
  94. #if defined(_tsan_enabled_)
  95. return true;
  96. #else
  97. return false;
  98. #endif
  99. }
  100. // Determines if msan present
  101. inline constexpr static bool MSanIsOn() noexcept {
  102. #if defined(_msan_enabled_)
  103. return true;
  104. #else
  105. return false;
  106. #endif
  107. }
  108. // Make memory region fully initialized (without changing its contents).
  109. inline static void Unpoison(const volatile void* a, size_t size) noexcept {
  110. #if defined(_msan_enabled_)
  111. __msan_unpoison(a, size);
  112. #else
  113. Y_UNUSED(a);
  114. Y_UNUSED(size);
  115. #endif
  116. }
  117. // Make memory region fully uninitialized (without changing its contents).
  118. // This is a legacy interface that does not update origin information. Use __msan_allocated_memory() instead.
  119. inline static void Poison(const volatile void* a, size_t size) noexcept {
  120. #if defined(_msan_enabled_)
  121. __msan_poison(a, size);
  122. #else
  123. Y_UNUSED(a);
  124. Y_UNUSED(size);
  125. #endif
  126. }
  127. // Checks that memory range is fully initialized, and reports an error if it is not.
  128. inline static void CheckMemIsInitialized(const volatile void* a, size_t size) noexcept {
  129. #if defined(_msan_enabled_)
  130. __msan_check_mem_is_initialized(a, size);
  131. #else
  132. Y_UNUSED(a);
  133. Y_UNUSED(size);
  134. #endif
  135. }
  136. inline static void MarkAsIntentionallyLeaked(const void* ptr) noexcept {
  137. #if defined(_asan_enabled_) || defined(_lsan_enabled_)
  138. __lsan_ignore_object(ptr);
  139. #else
  140. Y_UNUSED(ptr);
  141. #endif
  142. }
  143. #if defined(_tsan_enabled_)
  144. // defined in .cpp to avoid exposing problematic C-linkage version of AnnotateBenignRaceSized(...)
  145. void AnnotateBenignRaceSized(const char* file, int line,
  146. const volatile void* address,
  147. size_t size,
  148. const char* description) noexcept;
  149. #else
  150. inline static void AnnotateBenignRaceSized(const char* file, int line,
  151. const volatile void* address,
  152. size_t size,
  153. const char* description) noexcept {
  154. Y_UNUSED(file);
  155. Y_UNUSED(line);
  156. Y_UNUSED(address);
  157. Y_UNUSED(size);
  158. Y_UNUSED(description);
  159. }
  160. #endif
  161. inline static void Acquire(void* a) {
  162. #if defined(_tsan_enabled_)
  163. __tsan_acquire(a);
  164. #else
  165. Y_UNUSED(a);
  166. #endif
  167. }
  168. inline static void Release(void* a) {
  169. #if defined(_tsan_enabled_)
  170. __tsan_release(a);
  171. #else
  172. Y_UNUSED(a);
  173. #endif
  174. }
  175. } // namespace NSan