From ee9f67535e2ba2291a0e537eb5b0385b0f76d247 Mon Sep 17 00:00:00 2001 From: Gerhard Gruber Date: Thu, 6 Sep 2018 16:38:33 +0200 Subject: [PATCH 1/2] Fix memory corruption in case of pending callbacks on destruction of client. --- includes/cpp_redis/core/client.hpp | 8 ++++++++ sources/core/client.cpp | 29 ++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/includes/cpp_redis/core/client.hpp b/includes/cpp_redis/core/client.hpp index 3fa05e81..78d68057 100644 --- a/includes/cpp_redis/core/client.hpp +++ b/includes/cpp_redis/core/client.hpp @@ -1,4 +1,5 @@ // The MIT License (MIT) +// The MIT License (MIT) // // Copyright (c) 2015-2017 Simon Ninon // @@ -161,6 +162,13 @@ class client { //! void cancel_reconnect(void); + //! + //! Wait until all callbacks are completed. + //! + //! \return current instance + //! + client& wait_for_completion(void); + public: //! //! reply callback called whenever a reply is received diff --git a/sources/core/client.cpp b/sources/core/client.cpp index 7618d630..1f32f415 100644 --- a/sources/core/client.cpp +++ b/sources/core/client.cpp @@ -60,6 +60,11 @@ client::~client(void) { m_client.disconnect(true); } + // sparhawk@gmx.at + // If there are pending callbacks we have to wait until they are completed + // otherwise this will cause a memory corruption if they return after this point. + wait_for_completion(); + __CPP_REDIS_LOG(debug, "cpp_redis::client destroyed"); } @@ -125,6 +130,7 @@ client::disconnect(bool wait_for_removal) { //! make sure we clear buffer of unsent commands clear_callbacks(); + wait_for_completion(); __CPP_REDIS_LOG(info, "cpp_redis::client disconnected"); } @@ -201,11 +207,7 @@ client::sync_commit(void) { try_commit(); } - std::unique_lock lock_callback(m_callbacks_mutex); - __CPP_REDIS_LOG(debug, "cpp_redis::client waiting for callbacks to complete"); - m_sync_condvar.wait(lock_callback, [=] { return m_callbacks_running == 0 && m_commands.empty(); }); - __CPP_REDIS_LOG(debug, "cpp_redis::client finished waiting for callback completion"); - return *this; + return wait_for_completion(); } void @@ -215,11 +217,11 @@ client::try_commit(void) { m_client.commit(); __CPP_REDIS_LOG(info, "cpp_redis::client sent pipelined commands"); } - catch (const cpp_redis::redis_error&) { + catch (const cpp_redis::redis_error& e) { __CPP_REDIS_LOG(error, "cpp_redis::client could not send pipelined commands"); //! ensure commands are flushed clear_callbacks(); - throw; + throw e; } } @@ -250,8 +252,17 @@ client::connection_receive_handler(network::redis_connection&, reply& reply) { } } +client& client::wait_for_completion(void) +{ + std::unique_lock lock_callback(m_callbacks_mutex); + __CPP_REDIS_LOG(debug, "cpp_redis::client waiting for callbacks to complete"); + m_sync_condvar.wait(lock_callback, [=] { return m_callbacks_running == 0 && m_commands.empty(); }); + __CPP_REDIS_LOG(debug, "cpp_redis::client finished waiting for callback completion"); + return *this; +} + void -client::clear_callbacks(void) { +client::clear_callbacks() { if (m_commands.empty()) { return; } @@ -288,7 +299,7 @@ client::resend_failed_commands(void) { //! dequeue commands and move them to a local variable std::queue commands = std::move(m_commands); - while (commands.size() > 0) { + while (m_commands.size() > 0) { //! Reissue the pending command and its callback. unprotected_send(commands.front().command, commands.front().callback); From 8a9ab7a8b338a0751b627cb5b692bddaa63bb140 Mon Sep 17 00:00:00 2001 From: Gerhard Gruber Date: Thu, 6 Sep 2018 16:43:01 +0200 Subject: [PATCH 2/2] Formatted code to match current style. --- sources/core/client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/core/client.cpp b/sources/core/client.cpp index 1f32f415..bf19a10b 100644 --- a/sources/core/client.cpp +++ b/sources/core/client.cpp @@ -252,8 +252,8 @@ client::connection_receive_handler(network::redis_connection&, reply& reply) { } } -client& client::wait_for_completion(void) -{ +client& +client::wait_for_completion(void) { std::unique_lock lock_callback(m_callbacks_mutex); __CPP_REDIS_LOG(debug, "cpp_redis::client waiting for callbacks to complete"); m_sync_condvar.wait(lock_callback, [=] { return m_callbacks_running == 0 && m_commands.empty(); });