-
Notifications
You must be signed in to change notification settings - Fork 561
Heap-use-after-free when deleting while callback is still running #192
Description
Hey together,
currently I have a problem regarding the usage of two parallel redis connections from an application.
After usage, I want to close the connection by calling the function
--> client.disconnect(true);
From this point on, my address sanitizer build says there is a heap-use-after-free problem:
- 08/02/18 13:27:03 INFO [Redis] Disconnection of redis client... // Object 1 client.disconnect(true)
- ~Client: 0x0x61a00001e098 Running 0x0x61a00001e4f0 // Object 1 is deleted via destructor
- 08/02/18 13:27:03 INFO [Redis] Disconnection of redis client... // Object 2 client.disconnect(true)
- ~Client: 0x0x61a00001da98 Running 0x0x61a00001def0 // Object 2 is deleted via destructor
- Callback 0x0x61a00001e098 Running 0x0x61a00001e4f0 // Object 1 is still in use
=================================================================
==13580==ERROR: AddressSanitizer: heap-use-after-free on address 0x61a00001e4f0 at pc 0x0000006b8b79 bp 0x7fd5fe217d30 sp 0x7fd5fe217d20
WRITE of size 4 at 0x61a00001e4f0 thread T3
One can see that two redis client objects get disconnected and destroyed, but nevertheless we receive a callback of the already destroyed object.
Furthermore, one can see that this depends on the below mentioned function client::clear_callbacks
void
client::clear_callbacks(void) {
if (m_commands.empty()) {
return;
}
//! dequeue commands and move them to a local variable
std::queue<command_request> commands = std::move(m_commands);
m_callbacks_running += __CPP_REDIS_LENGTH(commands.size());
std::thread t(= mutable {
while (!commands.empty()) {
const auto& callback = commands.front().callback;
if (callback) {
reply r = {"network failure", reply::string_type::error};
callback(r);
}
--m_callbacks_running; // 0x0x61a00001e4f0
commands.pop();
}
m_sync_condvar.notify_all();
});
t.detach();
}
The function clear_callbacks gets called while both objects are still valid.
After calling the destructor of the objects, we get a callback from the thread created inside the function.
If there are any further questions, don´t hesitate to ask me.
Thanks in advance,
Andy