Skip to content

Commit

Permalink
Tell ASAN about fiber stacks
Browse files Browse the repository at this point in the history
Summary:ASAN needs to know about the stack extents. Currently it has no knowledge of
fibers and so it can give false positives, particularly in cases of no-return
(think exceptions).

See: google/sanitizers#189

This change along with a related ASAN diff fixes that, and I've verified it
fixes false positive test failures I'm seeing when throws happen from fibers.

Also rips out some hacks that attempted to work around the limitations of
ASAN these changes should fix.

This change depends on:
D3017630
D2952854
D3017619

And will also depend on rollout of libasan.so to /usr/local/fbcode platform dirs on all machines.

Reviewed By: andriigrynenko

Differential Revision: D2952899

fb-gh-sync-id: 19da779227c6c0f30c5755806325aa4cba364cfe
shipit-source-id: 19da779227c6c0f30c5755806325aa4cba364cfe
  • Loading branch information
andrewcox authored and Facebook Github Bot 1 committed Mar 17, 2016
1 parent d9e0b59 commit 2ea64dd
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 20 deletions.
19 changes: 3 additions & 16 deletions folly/experimental/fibers/Fiber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,8 @@ void Fiber::fiberFuncHelper(intptr_t fiber) {
reinterpret_cast<Fiber*>(fiber)->fiberFunc();
}

/*
* Some weird bug in ASAN causes fiberFunc to allocate boundless amounts of
* memory inside __asan_handle_no_return. Work around this in ASAN builds by
* tricking the compiler into thinking it may, someday, return.
*/
#ifdef FOLLY_SANITIZE_ADDRESS
volatile bool loopForever = true;
#else
static constexpr bool loopForever = true;
#endif

void Fiber::fiberFunc() {
while (loopForever) {
while (true) {
DCHECK_EQ(state_, NOT_STARTED);

threadId_ = localThreadId();
Expand Down Expand Up @@ -176,9 +165,8 @@ void Fiber::fiberFunc() {

state_ = INVALID;

fiberManager_.activeFiber_ = nullptr;
auto context = fiberManager_.deactivateFiber(this);

auto context = jumpContext(&fcontext_, &fiberManager_.mainContext_, 0);
DCHECK_EQ(reinterpret_cast<Fiber*>(context), this);
}
}
Expand All @@ -191,12 +179,11 @@ intptr_t Fiber::preempt(State state) {
DCHECK_EQ(state_, RUNNING);
DCHECK_NE(state, RUNNING);

fiberManager_.activeFiber_ = nullptr;
state_ = state;

recordStackPosition();

ret = jumpContext(&fcontext_, &fiberManager_.mainContext_, 0);
ret = fiberManager_.deactivateFiber(this);

DCHECK_EQ(fiberManager_.activeFiber_, this);
DCHECK_EQ(state_, READY_TO_RUN);
Expand Down
25 changes: 23 additions & 2 deletions folly/experimental/fibers/FiberManager-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,28 @@ inline void FiberManager::ensureLoopScheduled() {
loopController_->schedule();
}

inline intptr_t FiberManager::activateFiber(Fiber* fiber) {
DCHECK_EQ(activeFiber_, (Fiber*)nullptr);

#ifdef FOLLY_SANITIZE_ADDRESS
registerFiberActivationWithAsan(fiber);
#endif

activeFiber_ = fiber;
return jumpContext(&mainContext_, &fiber->fcontext_, fiber->data_);
}

inline intptr_t FiberManager::deactivateFiber(Fiber* fiber) {
DCHECK_EQ(activeFiber_, fiber);

#ifdef FOLLY_SANITIZE_ADDRESS
registerFiberDeactivationWithAsan(fiber);
#endif

activeFiber_ = nullptr;
return jumpContext(&fiber->fcontext_, &mainContext_, 0);
}

inline void FiberManager::runReadyFiber(Fiber* fiber) {
SCOPE_EXIT {
assert(currentFiber_ == nullptr);
Expand All @@ -74,8 +96,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {

while (fiber->state_ == Fiber::NOT_STARTED ||
fiber->state_ == Fiber::READY_TO_RUN) {
activeFiber_ = fiber;
jumpContext(&mainContext_, &fiber->fcontext_, fiber->data_);
activateFiber(fiber);
if (fiber->state_ == Fiber::AWAITING_IMMEDIATE) {
try {
immediateFunc_();
Expand Down
92 changes: 90 additions & 2 deletions folly/experimental/fibers/FiberManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@
#include <folly/experimental/fibers/Fiber.h>
#include <folly/experimental/fibers/LoopController.h>

#ifdef FOLLY_SANITIZE_ADDRESS

#include <dlfcn.h>

static void __asan_enter_fiber_weak(
void const* fiber_stack_base,
size_t fiber_stack_extent)
__attribute__((__weakref__("__asan_enter_fiber")));
static void __asan_exit_fiber_weak()
__attribute__((__weakref__("__asan_exit_fiber")));

typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t);
typedef void (*AsanExitFiberFuncPtr)();

namespace folly { namespace fibers {

static AsanEnterFiberFuncPtr getEnterFiberFunc();
static AsanExitFiberFuncPtr getExitFiberFunc();

}}

#endif

namespace folly { namespace fibers {

FOLLY_TLS FiberManager* FiberManager::currentFiberManager_ = nullptr;
Expand Down Expand Up @@ -88,7 +111,6 @@ Fiber* FiberManager::getFiber() {
++fiberId_;
bool recordStack = (options_.recordStackEvery != 0) &&
(fiberId_ % options_.recordStackEvery == 0);
fiber->init(recordStack);
return fiber;
}

Expand Down Expand Up @@ -139,12 +161,78 @@ void FiberManager::doFibersPoolResizing() {
maxFibersActiveLastPeriod_ = fibersActive_;
}

void FiberManager::FiberManager::FibersPoolResizer::operator()() {
void FiberManager::FibersPoolResizer::operator()() {
fiberManager_.doFibersPoolResizing();
fiberManager_.timeoutManager_->registerTimeout(
*this,
std::chrono::milliseconds(
fiberManager_.options_.fibersPoolResizePeriodMs));
}

#ifdef FOLLY_SANITIZE_ADDRESS

void FiberManager::registerFiberActivationWithAsan(Fiber* fiber) {
auto context = &fiber->fcontext_;
void* top = context->stackBase();
void* bottom = context->stackLimit();
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
static AsanEnterFiberFuncPtr fn = getEnterFiberFunc();
if (fn == nullptr) {
LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
} else {
fn(bottom, extent);
}
}

void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) {
(void)fiber; // currently unused

// Check if we can find a fiber exit function and call it if we find one
static AsanExitFiberFuncPtr fn = getExitFiberFunc();
if (fn == nullptr) {
LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
} else {
fn();
}
}

static AsanEnterFiberFuncPtr getEnterFiberFunc() {
AsanEnterFiberFuncPtr fn{nullptr};

// Check whether weak reference points to statically linked enter function
if (nullptr != (fn = &::__asan_enter_fiber_weak)) {
return fn;
}

// Check whether we can find a dynamically linked enter function
if (nullptr !=
(fn = (AsanEnterFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_enter_fiber"))) {
return fn;
}

// Couldn't find the function at all
return nullptr;
}

static AsanExitFiberFuncPtr getExitFiberFunc() {
AsanExitFiberFuncPtr fn{nullptr};

// Check whether weak reference points to statically linked exit function
if (nullptr != (fn = &::__asan_exit_fiber_weak)) {
return fn;
}

// Check whether we can find a dynamically linked enter function
if (nullptr !=
(fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) {
return fn;
}

// Couldn't find the function at all
return nullptr;
}

#endif // FOLLY_SANITIZE_ADDRESS
}}
13 changes: 13 additions & 0 deletions folly/experimental/fibers/FiberManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ class FiberManager : public ::folly::Executor {
AtomicLinkedListHook<RemoteTask> nextRemoteTask;
};

intptr_t activateFiber(Fiber* fiber);
intptr_t deactivateFiber(Fiber* fiber);

typedef folly::IntrusiveList<Fiber, &Fiber::listHook_> FiberTailQueue;

Fiber* activeFiber_{nullptr}; /**< active fiber, nullptr on main context */
Expand Down Expand Up @@ -450,6 +453,16 @@ class FiberManager : public ::folly::Executor {

void runReadyFiber(Fiber* fiber);
void remoteReadyInsert(Fiber* fiber);

#ifdef FOLLY_SANITIZE_ADDRESS

// 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.

void registerFiberActivationWithAsan(Fiber* fiber);
void registerFiberDeactivationWithAsan(Fiber* fiber);

#endif // FOLLY_SANITIZE_ADDRESS
};

/**
Expand Down

0 comments on commit 2ea64dd

Please sign in to comment.