Fix fibers asan integration for new asan APIs
authorIgor Sugak <sugak@fb.com>
Tue, 20 Sep 2016 07:51:26 +0000 (00:51 -0700)
committerFacebook Github Bot 6 <facebook-github-bot-6-bot@fb.com>
Tue, 20 Sep 2016 07:53:38 +0000 (00:53 -0700)
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

folly/fibers/Fiber.cpp
folly/fibers/Fiber.h
folly/fibers/FiberManager.cpp
folly/fibers/FiberManagerInternal-inl.h
folly/fibers/FiberManagerInternal.h

index afb72c07d386fb90bd08c0e274b0c4d4598e0f2a..aba1d44065a16860df7bff01c013b3238ee86b79 100644 (file)
@@ -126,6 +126,11 @@ void Fiber::fiberFuncHelper(intptr_t fiber) {
 }
 
 void Fiber::fiberFunc() {
+#ifdef FOLLY_SANITIZE_ADDRESS
+  fiberManager_.registerFinishSwitchStackWithAsan(
+      nullptr, &asanMainStackBase_, &asanMainStackSize_);
+#endif
+
   while (true) {
     DCHECK_EQ(state_, NOT_STARTED);
 
index 13f435de501c063ca20a73dd007c3cd47d0a1f88..062be3b5db18693cc9c69277d37512f81568b342 100644 (file)
@@ -184,6 +184,12 @@ class Fiber {
                                            queues */
   folly::IntrusiveListHook globalListHook_; /**< list hook for global list */
   std::thread::id threadId_{};
+
+#ifdef FOLLY_SANITIZE_ADDRESS
+  void* asanFakeStack_{nullptr};
+  const void* asanMainStackBase_{nullptr};
+  size_t asanMainStackSize_{0};
+#endif
 };
 }
 }
index d900bcff7bed15852273743d1024d01b6cf23163..9db0e87418282e1954969fb821ec68647a12eb7b 100644 (file)
 
 #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,
     size_t fiber_stack_extent)
-    __attribute__((__weakref__("__asan_enter_fiber")));
-static void __asan_exit_fiber_weak()
-    __attribute__((__weakref__("__asan_exit_fiber")));
+    __attribute__((__weakref__("__sanitizer_start_switch_fiber")));
+static void __sanitizer_finish_switch_fiber_weak(
+    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(
     void const /* nolint */ volatile* addr,
     size_t size) __attribute__((__weakref__("__asan_unpoison_memory_region")));
 
-typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t);
-typedef void (*AsanExitFiberFuncPtr)();
+typedef void (*AsanStartSwitchStackFuncPtr)(void**, void const*, size_t);
+typedef void (*AsanFinishSwitchStackFuncPtr)(void*, void const**, size_t*);
 typedef void (*AsanUnpoisonMemoryRegionFuncPtr)(
     void const /* nolint */ volatile*,
     size_t);
@@ -52,8 +56,8 @@ typedef void (*AsanUnpoisonMemoryRegionFuncPtr)(
 namespace folly {
 namespace fibers {
 
-static AsanEnterFiberFuncPtr getEnterFiberFunc();
-static AsanExitFiberFuncPtr getExitFiberFunc();
+static AsanStartSwitchStackFuncPtr getStartSwitchStackFunc();
+static AsanFinishSwitchStackFuncPtr getFinishSwitchStackFunc();
 static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc();
 }
 }
@@ -187,30 +191,29 @@ void FiberManager::FibersPoolResizer::operator()() {
 
 #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);
-
+void FiberManager::registerStartSwitchStackWithAsan(
+    void** saveFakeStack,
+    const void* stackBottom,
+    size_t stackSize) {
   // 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) {
     LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
   } else {
-    fn(bottom, extent);
+    fn(saveFakeStack, stackBottom, stackSize);
   }
 }
 
-void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) {
-  (void)fiber; // currently unused
-
+void FiberManager::registerFinishSwitchStackWithAsan(
+    void* saveFakeStack,
+    const void** saveStackBottom,
+    size_t* saveStackSize) {
   // 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) {
     LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
   } else {
-    fn();
+    fn(saveFakeStack, saveStackBottom, saveStackSize);
   }
 }
 
@@ -226,17 +229,17 @@ void FiberManager::unpoisonFiberStack(const Fiber* fiber) {
   }
 }
 
-static AsanEnterFiberFuncPtr getEnterFiberFunc() {
-  AsanEnterFiberFuncPtr fn{nullptr};
+static AsanStartSwitchStackFuncPtr getStartSwitchStackFunc() {
+  AsanStartSwitchStackFuncPtr fn{nullptr};
 
   // 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;
   }
 
   // Check whether we can find a dynamically linked enter function
-  if (nullptr !=
-      (fn = (AsanEnterFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_enter_fiber"))) {
+  if (nullptr != (fn = (AsanStartSwitchStackFuncPtr)dlsym(
+                      RTLD_DEFAULT, "__sanitizer_start_switch_fiber"))) {
     return fn;
   }
 
@@ -244,17 +247,17 @@ static AsanEnterFiberFuncPtr getEnterFiberFunc() {
   return nullptr;
 }
 
-static AsanExitFiberFuncPtr getExitFiberFunc() {
-  AsanExitFiberFuncPtr fn{nullptr};
+static AsanFinishSwitchStackFuncPtr getFinishSwitchStackFunc() {
+  AsanFinishSwitchStackFuncPtr fn{nullptr};
 
   // 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;
   }
 
   // Check whether we can find a dynamically linked exit function
-  if (nullptr !=
-      (fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) {
+  if (nullptr != (fn = (AsanFinishSwitchStackFuncPtr)dlsym(
+                      RTLD_DEFAULT, "__sanitizer_finish_switch_fiber"))) {
     return fn;
   }
 
index b0aa662d629b690d0dce302c19709b01464a53d7..abb7d70ffc03f5497116f8eb0f83289aad05c729 100644 (file)
@@ -62,7 +62,16 @@ inline intptr_t FiberManager::activateFiber(Fiber* fiber) {
   DCHECK_EQ(activeFiber_, (Fiber*)nullptr);
 
 #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
 
   activeFiber_ = fiber;
@@ -73,7 +82,21 @@ inline intptr_t FiberManager::deactivateFiber(Fiber* fiber) {
   DCHECK_EQ(activeFiber_, fiber);
 
 #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
 
   activeFiber_ = nullptr;
index ecea97a98e7c7c777bddffe8a1644c103bc79a09..12669c7c9cfaa98de1b1ecbc65394e68f706e348 100644 (file)
@@ -468,8 +468,14 @@ class FiberManager : public ::folly::Executor {
   // 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);
+  void registerStartSwitchStackWithAsan(
+      void** saveFakeStack,
+      const void* stackBase,
+      size_t stackSize);
+  void registerFinishSwitchStackWithAsan(
+      void* fakeStack,
+      const void** saveStackBase,
+      size_t* saveStackSize);
   void unpoisonFiberStack(const Fiber* fiber);
 
 #endif // FOLLY_SANITIZE_ADDRESS