evpp icon indicating copy to clipboard operation
evpp copied to clipboard

Invalid FdChannel when gdb is attached

Open smalhotra-spirent opened this issue 5 years ago • 1 comments

I have an evnsq consumer application that connects to nsqd. When the consumer is stopped by attaching gdb it is expected that the TCP connection to nsqd will break. But what I'm noticing is that libevent sometimes makes a call to FdChannel::HandleEvent with an invalid object in this scenario leading to a crash.

void FdChannel::HandleEvent(evpp_socket_t sockfd, short which, void* v) {
    FdChannel* c = (FdChannel*)v;
    c->HandleEvent(sockfd, which);
}

It appears that the callback is being made with an older channel object pointer (that has been disconnected most likely). I also see that evpp actually creates a new channel, but somewhere libevent still holds on to the older event handler.

Has anyone seen this issue before? If yes, what's the recommended solution? As of now, my consumer application crashes whenever I attach the debugger.

smalhotra-spirent avatar Aug 27 '19 10:08 smalhotra-spirent

After some more digging, this is what is happening. The issue is not with libevent calling back with an invalid FdChannel object. The problem occurs when a debugger is attached and the thread processing the libevent callback is stopped long enough that the TCP connection times out. Here's the sequence:

  1. libevent calls back into FdChannel::HandleEvent with both read and write bits set in the event. FdChannel::HandleEvent(evpp_socket_t sockfd, short which)
  2. The read_fn_() is then invoked
   if ((which & kReadable) && read_fn_) {
       read_fn_();
   }
  1. But by this time the TCP connection has timed out, resulting in the TCP connection reset and destruction of the FdChannel object.
core.dll!evpp::FdChannel::~FdChannel() Line 23    C++
[External Code]    
core.dll!evpp::Connector::~Connector() Line 43    C++
[External Code]    
core.dll!evpp::TCPClient::Connect::__l2::<lambda>() Line 53    C++
[External Code]    
core.dll!evpp::EventLoop::RunInLoop(std::function<void __cdecl(void)> && functor) Line 223    C++
core.dll!evpp::TCPClient::Connect() Line 56    C++
core.dll!evpp::TCPClient::Reconnect() Line 91    C++
core.dll!evpp::TCPClient::OnRemoveConnection(const std::shared_ptr<evpp::TCPConn> & c) Line 135    C++
[External Code]    
core.dll!evpp::TCPConn::HandleClose() Line 282    C++
core.dll!evpp::TCPConn::HandleError() Line 290    C++
core.dll!evpp::TCPConn::HandleRead() Line 210    C++
  1. By the time control comes back to process the write_fn_(), the FdChannel object has been destroyed, leading to the crash.
  if ((which & kWritable) && write_fn_) {
      write_fn_();
  }

smalhotra-spirent avatar Aug 30 '19 07:08 smalhotra-spirent