Summary:
I had a crash bug where an `EventBase` handler called a function, which tried to use the thread's EventBase as if it were its own:
```
auto evb = folly::EventBaseManager::get()->getEventBase();
// schedule work on evb, which calls evb->terminateLoopSoon() on completion
evb->loopForever();
```
This ended up invoking the `event_base_loop()` reentrantly, and corrupting the heap in a hard-to-debug way.
Reviewed By: djwatson
Differential Revision:
D3408155
fbshipit-source-id:
b8855aa3b390fa33e032ab295d386122d2cb872a
bool EventBase::loopBody(int flags) {
VLOG(5) << "EventBase(): Starting loop.";
+
+ DCHECK(!invokingLoop_)
+ << "Your code just tried to loop over an event base from inside another "
+ << "event base loop. Since libevent is not reentrant, this leads to "
+ << "undefined behavior in opt builds. Please fix immediately. For the "
+ << "common case of an inner function that needs to do some synchronous "
+ << "computation on an event-base, replace getEventBase() by a new, "
+ << "stack-allocated EvenBase.";
+ invokingLoop_ = true;
+ SCOPE_EXIT {
+ invokingLoop_ = false;
+ };
+
int res = 0;
bool ranLoopCallbacks;
bool blocking = !(flags & EVLOOP_NONBLOCK);
uint64_t nextLoopCnt_;
uint64_t latestLoopCnt_;
uint64_t startWork_;
+ // Prevent undefined behavior from invoking event_base_loop() reentrantly.
+ // This is needed since many projects use libevent-1.4, which lacks commit
+ // b557b175c00dc462c1fce25f6e7dd67121d2c001 from
+ // https://github.com/libevent/libevent/.
+ bool invokingLoop_{false};
// Observer to export counters
std::shared_ptr<EventBaseObserver> observer_;