#pragma once #include "defaults.h" extern "C" { // sanitizers API #if defined(_asan_enabled_) || defined(_lsan_enabled_) void __lsan_ignore_object(const void* p); #endif #if defined(_asan_enabled_) void __sanitizer_start_switch_fiber(void** fake_stack_save, const void* bottom, size_t size); void __sanitizer_finish_switch_fiber(void* fake_stack_save, const void** old_bottom, size_t* old_size); #endif #if defined(_msan_enabled_) void __msan_unpoison(const volatile void* a, size_t size); void __msan_poison(const volatile void* a, size_t size); void __msan_check_mem_is_initialized(const volatile void* x, size_t size); #endif #if defined(_tsan_enabled_) void __tsan_acquire(void* a); void __tsan_release(void* a); void* __tsan_get_current_fiber(void); void __tsan_destroy_fiber(void* fiber); void __tsan_switch_to_fiber(void* fiber, unsigned flags); #endif } // sanitizers API namespace NSan { class TFiberContext { public: TFiberContext() noexcept; TFiberContext(const void* stack, size_t len, const char* contName) noexcept; ~TFiberContext() noexcept { if (!IsMainFiber_) { #if defined(_asan_enabled_) if (Token_) { // destroy saved FakeStack void* activeFakeStack = nullptr; const void* activeStack = nullptr; size_t activeStackSize = 0; __sanitizer_start_switch_fiber(&activeFakeStack, (char*)Stack_, Len_); __sanitizer_finish_switch_fiber(Token_, &activeStack, &activeStackSize); __sanitizer_start_switch_fiber(nullptr, activeStack, activeStackSize); __sanitizer_finish_switch_fiber(activeFakeStack, nullptr, nullptr); } #endif #if defined(_tsan_enabled_) __tsan_destroy_fiber(CurrentTSanFiberContext_); #endif } } Y_FORCE_INLINE void BeforeSwitch(TFiberContext* old) noexcept { #if defined(_asan_enabled_) __sanitizer_start_switch_fiber(old ? &old->Token_ : nullptr, (char*)Stack_, Len_); #else (void)old; #endif #if defined(_tsan_enabled_) __tsan_switch_to_fiber(CurrentTSanFiberContext_, /*flags =*/0); #endif } void AfterSwitch() noexcept { #if defined(_asan_enabled_) __sanitizer_finish_switch_fiber(Token_, nullptr, nullptr); #endif } private: void* Token_; const void* Stack_; size_t Len_; const bool IsMainFiber_; #if defined(_tsan_enabled_) void* const CurrentTSanFiberContext_; #endif }; // Returns plain if no sanitizer enabled or sanitized otherwise // Ment to be used in test code for constants (timeouts, etc) template inline constexpr static T PlainOrUnderSanitizer(T plain, T sanitized) noexcept { #if defined(_tsan_enabled_) || defined(_msan_enabled_) || defined(_asan_enabled_) Y_UNUSED(plain); return sanitized; #else Y_UNUSED(sanitized); return plain; #endif } // Determines if asan present inline constexpr static bool ASanIsOn() noexcept { #if defined(_asan_enabled_) return true; #else return false; #endif } // Determines if tsan present inline constexpr static bool TSanIsOn() noexcept { #if defined(_tsan_enabled_) return true; #else return false; #endif } // Determines if msan present inline constexpr static bool MSanIsOn() noexcept { #if defined(_msan_enabled_) return true; #else return false; #endif } // Make memory region fully initialized (without changing its contents). inline static void Unpoison(const volatile void* a, size_t size) noexcept { #if defined(_msan_enabled_) __msan_unpoison(a, size); #else Y_UNUSED(a); Y_UNUSED(size); #endif } // Make memory region fully uninitialized (without changing its contents). // This is a legacy interface that does not update origin information. Use __msan_allocated_memory() instead. inline static void Poison(const volatile void* a, size_t size) noexcept { #if defined(_msan_enabled_) __msan_poison(a, size); #else Y_UNUSED(a); Y_UNUSED(size); #endif } // Checks that memory range is fully initialized, and reports an error if it is not. inline static void CheckMemIsInitialized(const volatile void* a, size_t size) noexcept { #if defined(_msan_enabled_) __msan_check_mem_is_initialized(a, size); #else Y_UNUSED(a); Y_UNUSED(size); #endif } inline static void MarkAsIntentionallyLeaked(const void* ptr) noexcept { #if defined(_asan_enabled_) || defined(_lsan_enabled_) __lsan_ignore_object(ptr); #else Y_UNUSED(ptr); #endif } #if defined(_tsan_enabled_) // defined in .cpp to avoid exposing problematic C-linkage version of AnnotateBenignRaceSized(...) void AnnotateBenignRaceSized(const char* file, int line, const volatile void* address, size_t size, const char* description) noexcept; #else inline static void AnnotateBenignRaceSized(const char* file, int line, const volatile void* address, size_t size, const char* description) noexcept { Y_UNUSED(file); Y_UNUSED(line); Y_UNUSED(address); Y_UNUSED(size); Y_UNUSED(description); } #endif inline static void Acquire(void* a) { #if defined(_tsan_enabled_) __tsan_acquire(a); #else Y_UNUSED(a); #endif } inline static void Release(void* a) { #if defined(_tsan_enabled_) __tsan_release(a); #else Y_UNUSED(a); #endif } } // namespace NSan