Commit 691cd11c authored by Igor Sugak's avatar Igor Sugak Committed by Facebook Github Bot 6

Fix fibers asan integration for new asan APIs

Summary:
Updating fibers code to use https://github.com/llvm-mirror/compiler-rt/commit/b0477747dfa8a9706f2c902e877e616aca51e06f

Patch by andriigrynenko!

Reviewed By: andrewcox

Differential Revision: D3500482

fbshipit-source-id: f51f4bb4ebf0d95a898eb1d4098459aa691acd61
parent 151e22b2
...@@ -126,6 +126,11 @@ void Fiber::fiberFuncHelper(intptr_t fiber) { ...@@ -126,6 +126,11 @@ void Fiber::fiberFuncHelper(intptr_t fiber) {
} }
void Fiber::fiberFunc() { void Fiber::fiberFunc() {
#ifdef FOLLY_SANITIZE_ADDRESS
fiberManager_.registerFinishSwitchStackWithAsan(
nullptr, &asanMainStackBase_, &asanMainStackSize_);
#endif
while (true) { while (true) {
DCHECK_EQ(state_, NOT_STARTED); DCHECK_EQ(state_, NOT_STARTED);
......
...@@ -184,6 +184,12 @@ class Fiber { ...@@ -184,6 +184,12 @@ class Fiber {
queues */ queues */
folly::IntrusiveListHook globalListHook_; /**< list hook for global list */ folly::IntrusiveListHook globalListHook_; /**< list hook for global list */
std::thread::id threadId_{}; std::thread::id threadId_{};
#ifdef FOLLY_SANITIZE_ADDRESS
void* asanFakeStack_{nullptr};
const void* asanMainStackBase_{nullptr};
size_t asanMainStackSize_{0};
#endif
}; };
} }
} }
......
...@@ -33,18 +33,22 @@ ...@@ -33,18 +33,22 @@
#include <dlfcn.h> #include <dlfcn.h>
static void __asan_enter_fiber_weak( static void __sanitizer_start_switch_fiber_weak(
void** fake_stack_save,
void const* fiber_stack_base, void const* fiber_stack_base,
size_t fiber_stack_extent) size_t fiber_stack_extent)
__attribute__((__weakref__("__asan_enter_fiber"))); __attribute__((__weakref__("__sanitizer_start_switch_fiber")));
static void __asan_exit_fiber_weak() static void __sanitizer_finish_switch_fiber_weak(
__attribute__((__weakref__("__asan_exit_fiber"))); void* fake_stack_save,
void const** old_stack_base,
size_t* old_stack_extent)
__attribute__((__weakref__("__sanitizer_finish_switch_fiber")));
static void __asan_unpoison_memory_region_weak( static void __asan_unpoison_memory_region_weak(
void const /* nolint */ volatile* addr, void const /* nolint */ volatile* addr,
size_t size) __attribute__((__weakref__("__asan_unpoison_memory_region"))); size_t size) __attribute__((__weakref__("__asan_unpoison_memory_region")));
typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t); typedef void (*AsanStartSwitchStackFuncPtr)(void**, void const*, size_t);
typedef void (*AsanExitFiberFuncPtr)(); typedef void (*AsanFinishSwitchStackFuncPtr)(void*, void const**, size_t*);
typedef void (*AsanUnpoisonMemoryRegionFuncPtr)( typedef void (*AsanUnpoisonMemoryRegionFuncPtr)(
void const /* nolint */ volatile*, void const /* nolint */ volatile*,
size_t); size_t);
...@@ -52,8 +56,8 @@ typedef void (*AsanUnpoisonMemoryRegionFuncPtr)( ...@@ -52,8 +56,8 @@ typedef void (*AsanUnpoisonMemoryRegionFuncPtr)(
namespace folly { namespace folly {
namespace fibers { namespace fibers {
static AsanEnterFiberFuncPtr getEnterFiberFunc(); static AsanStartSwitchStackFuncPtr getStartSwitchStackFunc();
static AsanExitFiberFuncPtr getExitFiberFunc(); static AsanFinishSwitchStackFuncPtr getFinishSwitchStackFunc();
static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc(); static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc();
} }
} }
...@@ -187,30 +191,29 @@ void FiberManager::FibersPoolResizer::operator()() { ...@@ -187,30 +191,29 @@ void FiberManager::FibersPoolResizer::operator()() {
#ifdef FOLLY_SANITIZE_ADDRESS #ifdef FOLLY_SANITIZE_ADDRESS
void FiberManager::registerFiberActivationWithAsan(Fiber* fiber) { void FiberManager::registerStartSwitchStackWithAsan(
auto context = &fiber->fcontext_; void** saveFakeStack,
void* top = context->stackBase(); const void* stackBottom,
void* bottom = context->stackLimit(); size_t stackSize) {
size_t extent = static_cast<char*>(top) - static_cast<char*>(bottom);
// Check if we can find a fiber enter function and call it if we find one // Check if we can find a fiber enter function and call it if we find one
static AsanEnterFiberFuncPtr fn = getEnterFiberFunc(); static AsanStartSwitchStackFuncPtr fn = getStartSwitchStackFunc();
if (fn == nullptr) { if (fn == nullptr) {
LOG(FATAL) << "The version of ASAN in use doesn't support fibers"; LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
} else { } else {
fn(bottom, extent); fn(saveFakeStack, stackBottom, stackSize);
} }
} }
void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) { void FiberManager::registerFinishSwitchStackWithAsan(
(void)fiber; // currently unused void* saveFakeStack,
const void** saveStackBottom,
size_t* saveStackSize) {
// Check if we can find a fiber exit function and call it if we find one // Check if we can find a fiber exit function and call it if we find one
static AsanExitFiberFuncPtr fn = getExitFiberFunc(); static AsanFinishSwitchStackFuncPtr fn = getFinishSwitchStackFunc();
if (fn == nullptr) { if (fn == nullptr) {
LOG(FATAL) << "The version of ASAN in use doesn't support fibers"; LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
} else { } else {
fn(); fn(saveFakeStack, saveStackBottom, saveStackSize);
} }
} }
...@@ -226,17 +229,17 @@ void FiberManager::unpoisonFiberStack(const Fiber* fiber) { ...@@ -226,17 +229,17 @@ void FiberManager::unpoisonFiberStack(const Fiber* fiber) {
} }
} }
static AsanEnterFiberFuncPtr getEnterFiberFunc() { static AsanStartSwitchStackFuncPtr getStartSwitchStackFunc() {
AsanEnterFiberFuncPtr fn{nullptr}; AsanStartSwitchStackFuncPtr fn{nullptr};
// Check whether weak reference points to statically linked enter function // Check whether weak reference points to statically linked enter function
if (nullptr != (fn = &::__asan_enter_fiber_weak)) { if (nullptr != (fn = &::__sanitizer_start_switch_fiber_weak)) {
return fn; return fn;
} }
// Check whether we can find a dynamically linked enter function // Check whether we can find a dynamically linked enter function
if (nullptr != if (nullptr != (fn = (AsanStartSwitchStackFuncPtr)dlsym(
(fn = (AsanEnterFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_enter_fiber"))) { RTLD_DEFAULT, "__sanitizer_start_switch_fiber"))) {
return fn; return fn;
} }
...@@ -244,17 +247,17 @@ static AsanEnterFiberFuncPtr getEnterFiberFunc() { ...@@ -244,17 +247,17 @@ static AsanEnterFiberFuncPtr getEnterFiberFunc() {
return nullptr; return nullptr;
} }
static AsanExitFiberFuncPtr getExitFiberFunc() { static AsanFinishSwitchStackFuncPtr getFinishSwitchStackFunc() {
AsanExitFiberFuncPtr fn{nullptr}; AsanFinishSwitchStackFuncPtr fn{nullptr};
// Check whether weak reference points to statically linked exit function // Check whether weak reference points to statically linked exit function
if (nullptr != (fn = &::__asan_exit_fiber_weak)) { if (nullptr != (fn = &::__sanitizer_finish_switch_fiber_weak)) {
return fn; return fn;
} }
// Check whether we can find a dynamically linked exit function // Check whether we can find a dynamically linked exit function
if (nullptr != if (nullptr != (fn = (AsanFinishSwitchStackFuncPtr)dlsym(
(fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) { RTLD_DEFAULT, "__sanitizer_finish_switch_fiber"))) {
return fn; return fn;
} }
......
...@@ -62,7 +62,16 @@ inline intptr_t FiberManager::activateFiber(Fiber* fiber) { ...@@ -62,7 +62,16 @@ inline intptr_t FiberManager::activateFiber(Fiber* fiber) {
DCHECK_EQ(activeFiber_, (Fiber*)nullptr); DCHECK_EQ(activeFiber_, (Fiber*)nullptr);
#ifdef FOLLY_SANITIZE_ADDRESS #ifdef FOLLY_SANITIZE_ADDRESS
registerFiberActivationWithAsan(fiber); DCHECK(!fiber->asanMainStackBase_);
DCHECK(!fiber->asanMainStackSize_);
auto stack = fiber->getStack();
void* asanFakeStack;
registerStartSwitchStackWithAsan(&asanFakeStack, stack.first, stack.second);
SCOPE_EXIT {
registerFinishSwitchStackWithAsan(asanFakeStack, nullptr, nullptr);
fiber->asanMainStackBase_ = nullptr;
fiber->asanMainStackSize_ = 0;
};
#endif #endif
activeFiber_ = fiber; activeFiber_ = fiber;
...@@ -73,7 +82,21 @@ inline intptr_t FiberManager::deactivateFiber(Fiber* fiber) { ...@@ -73,7 +82,21 @@ inline intptr_t FiberManager::deactivateFiber(Fiber* fiber) {
DCHECK_EQ(activeFiber_, fiber); DCHECK_EQ(activeFiber_, fiber);
#ifdef FOLLY_SANITIZE_ADDRESS #ifdef FOLLY_SANITIZE_ADDRESS
registerFiberDeactivationWithAsan(fiber); DCHECK(fiber->asanMainStackBase_);
DCHECK(fiber->asanMainStackSize_);
// Release fake stack if fiber is completed
auto saveFakeStackPtr =
fiber->state_ == Fiber::INVALID ? nullptr : &fiber->asanFakeStack_;
registerStartSwitchStackWithAsan(
saveFakeStackPtr, fiber->asanMainStackBase_, fiber->asanMainStackSize_);
SCOPE_EXIT {
registerFinishSwitchStackWithAsan(
fiber->asanFakeStack_,
&fiber->asanMainStackBase_,
&fiber->asanMainStackSize_);
fiber->asanFakeStack_ = nullptr;
};
#endif #endif
activeFiber_ = nullptr; activeFiber_ = nullptr;
......
...@@ -468,8 +468,14 @@ class FiberManager : public ::folly::Executor { ...@@ -468,8 +468,14 @@ class FiberManager : public ::folly::Executor {
// These methods notify ASAN when a fiber is entered/exited so that ASAN can // These methods notify ASAN when a fiber is entered/exited so that ASAN can
// find the right stack extents when it needs to poison/unpoison the stack. // find the right stack extents when it needs to poison/unpoison the stack.
void registerFiberActivationWithAsan(Fiber* fiber); void registerStartSwitchStackWithAsan(
void registerFiberDeactivationWithAsan(Fiber* fiber); void** saveFakeStack,
const void* stackBase,
size_t stackSize);
void registerFinishSwitchStackWithAsan(
void* fakeStack,
const void** saveStackBase,
size_t* saveStackSize);
void unpoisonFiberStack(const Fiber* fiber); void unpoisonFiberStack(const Fiber* fiber);
#endif // FOLLY_SANITIZE_ADDRESS #endif // FOLLY_SANITIZE_ADDRESS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment