From 0806af8f1b68c3f5c75f6330218f49365f53d695 Mon Sep 17 00:00:00 2001 From: Alexey Spiridonov Date: Fri, 10 Jun 2016 19:12:36 -0700 Subject: [PATCH] DCHECK on reentrant invocations of loop() 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 --- folly/io/async/EventBase.cpp | 13 +++++++++++++ folly/io/async/EventBase.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/folly/io/async/EventBase.cpp b/folly/io/async/EventBase.cpp index 2680d96c..9d5949e0 100644 --- a/folly/io/async/EventBase.cpp +++ b/folly/io/async/EventBase.cpp @@ -303,6 +303,19 @@ bool EventBase::loopOnce(int flags) { 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); diff --git a/folly/io/async/EventBase.h b/folly/io/async/EventBase.h index c65628d2..3fcf60e3 100644 --- a/folly/io/async/EventBase.h +++ b/folly/io/async/EventBase.h @@ -723,6 +723,11 @@ class EventBase : private boost::noncopyable, 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 observer_; -- 2.34.1