This is an automated email from the ASF dual-hosted git repository.
liaoxin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new a86882fa29c [fix](http) Fix EvHttpServer crash during graceful
shutdown in ASAN mode (#59769)
a86882fa29c is described below
commit a86882fa29caf859af3c7c2ac3dd05718586966f
Author: Xin Liao <[email protected]>
AuthorDate: Wed Jan 14 09:58:03 2026 +0800
[fix](http) Fix EvHttpServer crash during graceful shutdown in ASAN mode
(#59769)
The crash occurred because evhttp was created as a local shared_ptr in
the lambda function, and its destruction happened after
event_base_dispatch returned. This caused use-after-free issues when
ASAN/UBSAN tried to verify the object dynamic type during shared_ptr
destruction.
Fix by:
1. Moving evhttp objects to class member _evhttp_servers for explicit
lifecycle management
2. Reordering resource cleanup in stop():
- Close server_fd first to reject new connections
- Break event loops to make dispatch return
- Wait for worker threads to finish
- Clear evhttp before event_base (correct dependency order)
---
be/src/http/ev_http_server.cpp | 49 +++++++++++++++++++++++++++++++-----------
be/src/http/ev_http_server.h | 4 +++-
2 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/be/src/http/ev_http_server.cpp b/be/src/http/ev_http_server.cpp
index 457cf0e0322..ceb53df9180 100644
--- a/be/src/http/ev_http_server.cpp
+++ b/be/src/http/ev_http_server.cpp
@@ -117,16 +117,14 @@ void EvHttpServer::start() {
.set_min_threads(_num_workers)
.set_max_threads(_num_workers)
.build(&_workers));
- for (int i = 0; i < _num_workers; ++i) {
- auto status = _workers->submit_func([this, i]() {
- std::shared_ptr<event_base> base;
- {
- std::lock_guard lock(_event_bases_lock);
- base = _event_bases[i];
- }
- /* Create a new evhttp object to handle requests. */
- std::shared_ptr<evhttp> http(evhttp_new(base.get()),
+ // Pre-create all evhttp objects and store them as class members
+ // to ensure proper lifecycle management during shutdown
+ {
+ std::lock_guard lock(_event_bases_lock);
+ _evhttp_servers.resize(_num_workers);
+ for (int i = 0; i < _num_workers; ++i) {
+ std::shared_ptr<evhttp> http(evhttp_new(_event_bases[i].get()),
[](evhttp* http) { evhttp_free(http);
});
CHECK(http != nullptr) << "Couldn't create an evhttp.";
@@ -136,6 +134,17 @@ void EvHttpServer::start() {
evhttp_set_newreqcb(http.get(), on_connection, this);
evhttp_set_gencb(http.get(), on_request, this);
+ _evhttp_servers[i] = http;
+ }
+ }
+
+ for (int i = 0; i < _num_workers; ++i) {
+ auto status = _workers->submit_func([this, i]() {
+ std::shared_ptr<event_base> base;
+ {
+ std::lock_guard lock(_event_bases_lock);
+ base = _event_bases[i];
+ }
event_base_dispatch(base.get());
});
CHECK(status.ok());
@@ -143,15 +152,31 @@ void EvHttpServer::start() {
}
void EvHttpServer::stop() {
+ // 1. Close server fd first to reject new connections
+ close(_server_fd);
+ _server_fd = -1;
+
+ // 2. Break all event loops to make dispatch return
{
std::lock_guard<std::mutex> lock(_event_bases_lock);
for (int i = 0; i < _num_workers; ++i) {
- event_base_loopbreak(_event_bases[i].get());
+ if (_event_bases[i]) {
+ event_base_loopbreak(_event_bases[i].get());
+ }
}
}
+
+ // 3. Wait for all worker threads to finish event_base_dispatch
_workers->shutdown();
- _event_bases.clear();
- close(_server_fd);
+
+ // 4. Now it's safe to cleanup - all worker threads have exited
+ // Clear evhttp before event_base since evhttp depends on event_base
+ {
+ std::lock_guard<std::mutex> lock(_event_bases_lock);
+ _evhttp_servers.clear();
+ _event_bases.clear();
+ }
+
_started = false;
}
diff --git a/be/src/http/ev_http_server.h b/be/src/http/ev_http_server.h
index d74a8cb4efd..fa1c5a27928 100644
--- a/be/src/http/ev_http_server.h
+++ b/be/src/http/ev_http_server.h
@@ -27,6 +27,7 @@
#include "util/path_trie.hpp"
struct event_base;
+struct evhttp;
namespace doris {
@@ -74,8 +75,9 @@ private:
int _server_fd = -1;
std::unique_ptr<ThreadPool> _workers;
- std::mutex _event_bases_lock; // protect _event_bases
+ std::mutex _event_bases_lock; // protect _event_bases and _evhttp_servers
std::vector<std::shared_ptr<event_base>> _event_bases;
+ std::vector<std::shared_ptr<evhttp>> _evhttp_servers;
std::mutex _handler_lock;
PathTrie<HttpHandler*> _get_handlers;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]