Commit 6959fbe7 authored by Marcus Holland-Moritz's avatar Marcus Holland-Moritz Committed by Facebook Github Bot 4

Unpoison stack memory before deallocation

Summary:
This is a workaround (maybe even the correct fix if it turns out that ASan
can't detect this FP case) for the problem described in

  https://llvm.org/bugs/show_bug.cgi?id=27627

where a memory region previously allocated by a fiber stack can overlap with
the region of an mmap'd file. Accessing parts of the mmap'd file close to
the stack region will trigger a false positive ASan error.

This change makes sure each fiber explicitly unpoisons its stack memory by
calling __asan_unpoison_memory_region in an ASan-enabled build.

Reviewed By: yhfung

Differential Revision: D3257924

fb-gh-sync-id: 484062e80af67dfd39d2eaf3cbb52fa3483924eb
fbshipit-source-id: 484062e80af67dfd39d2eaf3cbb52fa3483924eb
parent 1c523f26
......@@ -111,6 +111,9 @@ void Fiber::init(bool recordStackUsed) {
}
Fiber::~Fiber() {
#ifdef FOLLY_SANITIZE_ADDRESS
fiberManager_.unpoisonFiberStack(this);
#endif
fiberManager_.stackAllocator_.deallocate(
static_cast<unsigned char*>(fcontext_.stackLimit()),
fiberManager_.options_.stackSize);
......
......@@ -36,15 +36,22 @@ static void __asan_enter_fiber_weak(
__attribute__((__weakref__("__asan_enter_fiber")));
static void __asan_exit_fiber_weak()
__attribute__((__weakref__("__asan_exit_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 (*AsanUnpoisonMemoryRegionFuncPtr)(
void const /* nolint */ volatile*,
size_t);
namespace folly {
namespace fibers {
static AsanEnterFiberFuncPtr getEnterFiberFunc();
static AsanExitFiberFuncPtr getExitFiberFunc();
static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc();
}
}
......@@ -199,6 +206,18 @@ void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) {
}
}
void FiberManager::unpoisonFiberStack(const Fiber* fiber) {
auto stack = fiber->getStack();
// Check if we can find a fiber enter function and call it if we find one
static AsanUnpoisonMemoryRegionFuncPtr fn = getUnpoisonMemoryRegionFunc();
if (fn == nullptr) {
LOG(FATAL) << "This version of ASAN doesn't support memory unpoisoning";
} else {
fn(stack.first, stack.second);
}
}
static AsanEnterFiberFuncPtr getEnterFiberFunc() {
AsanEnterFiberFuncPtr fn{nullptr};
......@@ -225,7 +244,7 @@ static AsanExitFiberFuncPtr getExitFiberFunc() {
return fn;
}
// Check whether we can find a dynamically linked enter function
// Check whether we can find a dynamically linked exit function
if (nullptr !=
(fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) {
return fn;
......@@ -235,6 +254,24 @@ static AsanExitFiberFuncPtr getExitFiberFunc() {
return nullptr;
}
static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc() {
AsanUnpoisonMemoryRegionFuncPtr fn{nullptr};
// Check whether weak reference points to statically linked unpoison function
if (nullptr != (fn = &::__asan_unpoison_memory_region_weak)) {
return fn;
}
// Check whether we can find a dynamically linked unpoison function
if (nullptr != (fn = (AsanUnpoisonMemoryRegionFuncPtr)dlsym(
RTLD_DEFAULT, "__asan_unpoison_memory_region"))) {
return fn;
}
// Couldn't find the function at all
return nullptr;
}
#endif // FOLLY_SANITIZE_ADDRESS
}
}
......@@ -464,6 +464,7 @@ class FiberManager : public ::folly::Executor {
void registerFiberActivationWithAsan(Fiber* fiber);
void registerFiberDeactivationWithAsan(Fiber* fiber);
void unpoisonFiberStack(const Fiber* fiber);
#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