Skip to content

Commit 2ea64dd

Browse files
andrewcoxFacebook Github Bot 1
authored andcommitted
Tell ASAN about fiber stacks
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
1 parent d9e0b59 commit 2ea64dd

4 files changed

Lines changed: 129 additions & 20 deletions

File tree

folly/experimental/fibers/Fiber.cpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -132,19 +132,8 @@ void Fiber::fiberFuncHelper(intptr_t fiber) {
132132
reinterpret_cast<Fiber*>(fiber)->fiberFunc();
133133
}
134134

135-
/*
136-
* Some weird bug in ASAN causes fiberFunc to allocate boundless amounts of
137-
* memory inside __asan_handle_no_return. Work around this in ASAN builds by
138-
* tricking the compiler into thinking it may, someday, return.
139-
*/
140-
#ifdef FOLLY_SANITIZE_ADDRESS
141-
volatile bool loopForever = true;
142-
#else
143-
static constexpr bool loopForever = true;
144-
#endif
145-
146135
void Fiber::fiberFunc() {
147-
while (loopForever) {
136+
while (true) {
148137
DCHECK_EQ(state_, NOT_STARTED);
149138

150139
threadId_ = localThreadId();
@@ -176,9 +165,8 @@ void Fiber::fiberFunc() {
176165

177166
state_ = INVALID;
178167

179-
fiberManager_.activeFiber_ = nullptr;
168+
auto context = fiberManager_.deactivateFiber(this);
180169

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

194-
fiberManager_.activeFiber_ = nullptr;
195182
state_ = state;
196183

197184
recordStackPosition();
198185

199-
ret = jumpContext(&fcontext_, &fiberManager_.mainContext_, 0);
186+
ret = fiberManager_.deactivateFiber(this);
200187

201188
DCHECK_EQ(fiberManager_.activeFiber_, this);
202189
DCHECK_EQ(state_, READY_TO_RUN);

folly/experimental/fibers/FiberManager-inl.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,28 @@ inline void FiberManager::ensureLoopScheduled() {
5858
loopController_->schedule();
5959
}
6060

61+
inline intptr_t FiberManager::activateFiber(Fiber* fiber) {
62+
DCHECK_EQ(activeFiber_, (Fiber*)nullptr);
63+
64+
#ifdef FOLLY_SANITIZE_ADDRESS
65+
registerFiberActivationWithAsan(fiber);
66+
#endif
67+
68+
activeFiber_ = fiber;
69+
return jumpContext(&mainContext_, &fiber->fcontext_, fiber->data_);
70+
}
71+
72+
inline intptr_t FiberManager::deactivateFiber(Fiber* fiber) {
73+
DCHECK_EQ(activeFiber_, fiber);
74+
75+
#ifdef FOLLY_SANITIZE_ADDRESS
76+
registerFiberDeactivationWithAsan(fiber);
77+
#endif
78+
79+
activeFiber_ = nullptr;
80+
return jumpContext(&fiber->fcontext_, &mainContext_, 0);
81+
}
82+
6183
inline void FiberManager::runReadyFiber(Fiber* fiber) {
6284
SCOPE_EXIT {
6385
assert(currentFiber_ == nullptr);
@@ -74,8 +96,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
7496

7597
while (fiber->state_ == Fiber::NOT_STARTED ||
7698
fiber->state_ == Fiber::READY_TO_RUN) {
77-
activeFiber_ = fiber;
78-
jumpContext(&mainContext_, &fiber->fcontext_, fiber->data_);
99+
activateFiber(fiber);
79100
if (fiber->state_ == Fiber::AWAITING_IMMEDIATE) {
80101
try {
81102
immediateFunc_();

folly/experimental/fibers/FiberManager.cpp

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,29 @@
2626
#include <folly/experimental/fibers/Fiber.h>
2727
#include <folly/experimental/fibers/LoopController.h>
2828

29+
#ifdef FOLLY_SANITIZE_ADDRESS
30+
31+
#include <dlfcn.h>
32+
33+
static void __asan_enter_fiber_weak(
34+
void const* fiber_stack_base,
35+
size_t fiber_stack_extent)
36+
__attribute__((__weakref__("__asan_enter_fiber")));
37+
static void __asan_exit_fiber_weak()
38+
__attribute__((__weakref__("__asan_exit_fiber")));
39+
40+
typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t);
41+
typedef void (*AsanExitFiberFuncPtr)();
42+
43+
namespace folly { namespace fibers {
44+
45+
static AsanEnterFiberFuncPtr getEnterFiberFunc();
46+
static AsanExitFiberFuncPtr getExitFiberFunc();
47+
48+
}}
49+
50+
#endif
51+
2952
namespace folly { namespace fibers {
3053

3154
FOLLY_TLS FiberManager* FiberManager::currentFiberManager_ = nullptr;
@@ -88,7 +111,6 @@ Fiber* FiberManager::getFiber() {
88111
++fiberId_;
89112
bool recordStack = (options_.recordStackEvery != 0) &&
90113
(fiberId_ % options_.recordStackEvery == 0);
91-
fiber->init(recordStack);
92114
return fiber;
93115
}
94116

@@ -139,12 +161,78 @@ void FiberManager::doFibersPoolResizing() {
139161
maxFibersActiveLastPeriod_ = fibersActive_;
140162
}
141163

142-
void FiberManager::FiberManager::FibersPoolResizer::operator()() {
164+
void FiberManager::FibersPoolResizer::operator()() {
143165
fiberManager_.doFibersPoolResizing();
144166
fiberManager_.timeoutManager_->registerTimeout(
145167
*this,
146168
std::chrono::milliseconds(
147169
fiberManager_.options_.fibersPoolResizePeriodMs));
148170
}
149171

172+
#ifdef FOLLY_SANITIZE_ADDRESS
173+
174+
void FiberManager::registerFiberActivationWithAsan(Fiber* fiber) {
175+
auto context = &fiber->fcontext_;
176+
void* top = context->stackBase();
177+
void* bottom = context->stackLimit();
178+
size_t extent = static_cast<char*>(top) - static_cast<char*>(bottom);
179+
180+
// Check if we can find a fiber enter function and call it if we find one
181+
static AsanEnterFiberFuncPtr fn = getEnterFiberFunc();
182+
if (fn == nullptr) {
183+
LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
184+
} else {
185+
fn(bottom, extent);
186+
}
187+
}
188+
189+
void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) {
190+
(void)fiber; // currently unused
191+
192+
// Check if we can find a fiber exit function and call it if we find one
193+
static AsanExitFiberFuncPtr fn = getExitFiberFunc();
194+
if (fn == nullptr) {
195+
LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
196+
} else {
197+
fn();
198+
}
199+
}
200+
201+
static AsanEnterFiberFuncPtr getEnterFiberFunc() {
202+
AsanEnterFiberFuncPtr fn{nullptr};
203+
204+
// Check whether weak reference points to statically linked enter function
205+
if (nullptr != (fn = &::__asan_enter_fiber_weak)) {
206+
return fn;
207+
}
208+
209+
// Check whether we can find a dynamically linked enter function
210+
if (nullptr !=
211+
(fn = (AsanEnterFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_enter_fiber"))) {
212+
return fn;
213+
}
214+
215+
// Couldn't find the function at all
216+
return nullptr;
217+
}
218+
219+
static AsanExitFiberFuncPtr getExitFiberFunc() {
220+
AsanExitFiberFuncPtr fn{nullptr};
221+
222+
// Check whether weak reference points to statically linked exit function
223+
if (nullptr != (fn = &::__asan_exit_fiber_weak)) {
224+
return fn;
225+
}
226+
227+
// Check whether we can find a dynamically linked enter function
228+
if (nullptr !=
229+
(fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) {
230+
return fn;
231+
}
232+
233+
// Couldn't find the function at all
234+
return nullptr;
235+
}
236+
237+
#endif // FOLLY_SANITIZE_ADDRESS
150238
}}

folly/experimental/fibers/FiberManager.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,9 @@ class FiberManager : public ::folly::Executor {
337337
AtomicLinkedListHook<RemoteTask> nextRemoteTask;
338338
};
339339

340+
intptr_t activateFiber(Fiber* fiber);
341+
intptr_t deactivateFiber(Fiber* fiber);
342+
340343
typedef folly::IntrusiveList<Fiber, &Fiber::listHook_> FiberTailQueue;
341344

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

451454
void runReadyFiber(Fiber* fiber);
452455
void remoteReadyInsert(Fiber* fiber);
456+
457+
#ifdef FOLLY_SANITIZE_ADDRESS
458+
459+
// These methods notify ASAN when a fiber is entered/exited so that ASAN can
460+
// find the right stack extents when it needs to poison/unpoison the stack.
461+
462+
void registerFiberActivationWithAsan(Fiber* fiber);
463+
void registerFiberDeactivationWithAsan(Fiber* fiber);
464+
465+
#endif // FOLLY_SANITIZE_ADDRESS
453466
};
454467

455468
/**

0 commit comments

Comments
 (0)