#include "sanitizers.h"
#include "thread.h"
#if defined(_asan_enabled_)
extern "C" {
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(_tsan_enabled_)
#if defined(__clang_major__) && (__clang_major__ >= 9)
extern "C" {
void* __tsan_get_current_fiber(void);
void* __tsan_create_fiber(unsigned flags);
void __tsan_destroy_fiber(void* fiber);
void __tsan_switch_to_fiber(void* fiber, unsigned flags);
void __tsan_set_fiber_name(void* fiber, const char* name);
}
#else
namespace {
void* __tsan_get_current_fiber(void) {
return nullptr;
}
void* __tsan_create_fiber(unsigned) {
return nullptr;
}
void __tsan_destroy_fiber(void*) {
}
void __tsan_switch_to_fiber(void*, unsigned) {
}
void __tsan_set_fiber_name(void*, const char*) {
}
}
#endif
#endif
using namespace NSan;
TFiberContext::TFiberContext() noexcept
: Token_(nullptr)
, IsMainFiber_(true)
#if defined(_tsan_enabled_)
, CurrentTSanFiberContext_(__tsan_get_current_fiber())
#endif
{
TCurrentThreadLimits sl;
Stack_ = sl.StackBegin;
Len_ = sl.StackLength;
#if defined(_tsan_enabled_)
static constexpr char MainFiberName[] = "main_fiber";
__tsan_set_fiber_name(CurrentTSanFiberContext_, MainFiberName);
#endif
}
TFiberContext::TFiberContext(const void* stack, size_t len, const char* contName) noexcept
: Token_(nullptr)
, Stack_(stack)
, Len_(len)
, IsMainFiber_(false)
#if defined(_tsan_enabled_)
, CurrentTSanFiberContext_(__tsan_create_fiber(/*flags =*/0))
#endif
{
(void)contName;
#if defined(_tsan_enabled_)
__tsan_set_fiber_name(CurrentTSanFiberContext_, contName);
#endif
}
TFiberContext::~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
}
}
void TFiberContext::BeforeFinish() noexcept {
#if defined(_asan_enabled_)
__sanitizer_start_switch_fiber(nullptr, nullptr, 0);
#else
(void)Token_;
(void)Stack_;
(void)Len_;
#endif
}
void TFiberContext::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 TFiberContext::AfterSwitch() noexcept {
#if defined(_asan_enabled_)
__sanitizer_finish_switch_fiber(Token_, nullptr, nullptr);
#endif
}
void TFiberContext::AfterStart() noexcept {
#if defined(_asan_enabled_)
__sanitizer_finish_switch_fiber(nullptr, nullptr, nullptr);
#endif
}
#if defined(_tsan_enabled_)
extern "C" {
// This function should not be directly exposed in headers
// due to signature variations among contrib headers.
void AnnotateBenignRaceSized(const char* file, int line,
const volatile void* address,
size_t size,
const char* description);
}
void NSan::AnnotateBenignRaceSized(const char* file, int line,
const volatile void* address,
size_t size,
const char* description) noexcept {
::AnnotateBenignRaceSized(file, line, address, size, description);
}
#endif