From 1b51d398fb0c431ccad3ac7177bc4c565807b949 Mon Sep 17 00:00:00 2001 From: anon Date: Fri, 19 Feb 2021 22:27:28 +0000 Subject: [PATCH 1/2] async_protocol_handler_config: add segfault demo --- tests/unit_tests/epee_boosted_tcp_server.cpp | 75 +++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp index e99666eb1..06e076a3a 100644 --- a/tests/unit_tests/epee_boosted_tcp_server.cpp +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -143,14 +143,24 @@ TEST(test_epee_connection, test_lifetime) static constexpr bool handshake_complete() noexcept { return true; } }; + using functional_obj_t = std::function; struct command_handler_t: epee::levin::levin_commands_handler { size_t delay; - command_handler_t(size_t delay = 0): delay(delay) {} + functional_obj_t on_connection_close_f; + command_handler_t(size_t delay = 0, + functional_obj_t on_connection_close_f = nullptr + ): + delay(delay), + on_connection_close_f(on_connection_close_f) + {} virtual int invoke(int, const epee::span, epee::byte_slice&, context_t&) override { epee::misc_utils::sleep_no_w(delay); return {}; } virtual int notify(int, const epee::span, context_t&) override { return {}; } virtual void callback(context_t&) override {} virtual void on_connection_new(context_t&) override {} - virtual void on_connection_close(context_t&) override {} + virtual void on_connection_close(context_t&) override { + if (on_connection_close_f) + on_connection_close_f(); + } virtual ~command_handler_t() override {} static void destroy(epee::levin::levin_commands_handler* ptr) { delete ptr; } }; @@ -168,6 +178,14 @@ TEST(test_epee_connection, test_lifetime) using work_ptr = std::shared_ptr; using workers_t = std::vector; using server_t = epee::net_utils::boosted_tcp_server; + using lock_t = std::mutex; + using lock_guard_t = std::lock_guard; + using connection_weak_ptr = boost::weak_ptr; + struct shared_conn_t { + lock_t lock; + connection_weak_ptr conn; + }; + using shared_conn_ptr = std::shared_ptr; io_context_t io_context; work_ptr work(std::make_shared(io_context)); @@ -255,6 +273,7 @@ TEST(test_epee_connection, test_lifetime) ASSERT_TRUE(index == N * N); ASSERT_TRUE(shared_state->get_connections_count() == 0); + while (shared_state->sock_count); ASSERT_TRUE(shared_state->get_connections_count() == 0); constexpr auto DELAY = 30; constexpr auto TIMEOUT = 1; @@ -273,6 +292,58 @@ TEST(test_epee_connection, test_lifetime) shared_state->close(tag); ASSERT_TRUE(shared_state->get_connections_count() == 0); } + + while (shared_state->sock_count); + constexpr auto ZERO_DELAY = 0; + size_t counter = 0; + shared_state->set_handler(new command_handler_t(ZERO_DELAY, + [&counter]{ + ASSERT_TRUE(counter++ == 0); + } + ), + &command_handler_t::destroy + ); + connection_ptr conn(new connection_t(io_context, shared_state, {}, {})); + conn->socket().connect(endpoint); + conn->start({}, {}); + ASSERT_TRUE(shared_state->get_connections_count() == 1); + shared_state->del_out_connections(1); + ASSERT_TRUE(shared_state->get_connections_count() == 0); + conn.reset(); + + while (shared_state->sock_count); + shared_conn_ptr shared_conn(std::make_shared()); + shared_state->set_handler(new command_handler_t(ZERO_DELAY, + [shared_state, shared_conn]{ + { + connection_ptr conn; + { + lock_guard_t guard(shared_conn->lock); + conn = std::move(shared_conn->conn.lock()); + } + if (conn) + conn->cancel(); + } + const auto success = shared_state->foreach_connection([](context_t&){ + return true; + }); + ASSERT_TRUE(success); + } + ), + &command_handler_t::destroy + ); + for (auto i = 0; i < N; ++i) { + { + connection_ptr conn(new connection_t(io_context, shared_state, {}, {})); + conn->socket().connect(endpoint); + conn->start({}, {}); + lock_guard_t guard(shared_conn->lock); + shared_conn->conn = conn; + } + ASSERT_TRUE(shared_state->get_connections_count() == 1); + shared_state->del_out_connections(1); + ASSERT_TRUE(shared_state->get_connections_count() == 0); + } }); for (auto& w: workers) { From 80125a2f773d208005cfbb03def39fb58aa6806e Mon Sep 17 00:00:00 2001 From: anon Date: Fri, 19 Feb 2021 22:27:29 +0000 Subject: [PATCH 2/2] async_protocol_handler_config: remove connection correctly --- contrib/epee/include/net/levin_protocol_handler_async.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index 635876589..f6b73a2d5 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -787,7 +787,7 @@ void async_protocol_handler_config::delete_connections(siz { auto i = connections.end() - 1; async_protocol_handler *conn = m_connects.at(*i); - del_connection(conn); + m_connects.erase(*i); conn->close(); connections.erase(i); }