cpp_redis icon indicating copy to clipboard operation
cpp_redis copied to clipboard

Heap-use-after-free when deleting while callback is still running

Open boflexman opened this issue 6 years ago • 1 comments

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

boflexman avatar Aug 02 '18 12:08 boflexman

I submitted a PR to fix this issue as I tracked it down to callbacks not being completed while the object is already destroyed. Looks like this issue https://github.com/Cylix/cpp_redis/issues/198 is reporting the same problem.

skeetor avatar Sep 06 '18 14:09 skeetor