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();
state_ = INVALID;
- fiberManager_.activeFiber_ = nullptr;
+ auto context = fiberManager_.deactivateFiber(this);
- auto context = jumpContext(&fcontext_, &fiberManager_.mainContext_, 0);
DCHECK_EQ(reinterpret_cast<Fiber*>(context), this);
}
}
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);
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);
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_();
#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;
++fiberId_;
bool recordStack = (options_.recordStackEvery != 0) &&
(fiberId_ % options_.recordStackEvery == 0);
- fiber->init(recordStack);
return fiber;
}
maxFibersActiveLastPeriod_ = fibersActive_;
}
-void FiberManager::FiberManager::FibersPoolResizer::operator()() {
+void FiberManager::FibersPoolResizer::operator()() {
fiberManager_.doFibersPoolResizing();
fiberManager_.timeoutManager_->registerTimeout(
*this,
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
}}
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 */
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
};
/**