capnproto icon indicating copy to clipboard operation
capnproto copied to clipboard

Destroying an RpcClient with outstdanding streaming calls triggers an "eventLoop != nullptr" assertion

Open fabiorossetto opened this issue 1 year ago • 1 comments

This issue was introduced in "Fix premature cancellation of streaming calls when capability dropped." (db470e67d284a1f345d2997b7dcd12e43f6c87d8)

I have a server that can stream data to a client. When I destroy the server, I see the following happening:

  • AsyncIoContext is destroyed, which leads to...
  • LowLevelAsyncIoProviderImpl being destroyed.
  • LowLevelAsyncIoProviderImpl owns an EventLoop and a WaitScope. The wait scope is destroyed first, which causes the thread local event loop to be reset.
  • After the WaitScope destructor, the EventLoop destructor is called. The EventLoop destructor processes the daemons
  • Through a path that I could not reconstruct, one of the daemons calls the RpcClient destructor. My application never uses detach, so I'm not sure how this happens. Perhaps through the detach call at capability.c++:852, or the one at rpc.c++:2465
  • The RpcClient destructor creates a Task in a TaskSet, which can be done only if there is a current event loop. But such loop does not exist anymore because WaitScope was destroyed already
  • capnp crashes complaining there is no event loop

The problem can be circumvented by calling cancelAllDetached before WaitScope is destroyed.

I guess it might make sense to add a call to cancelAllDetached to the destructor of LowLevelAsyncIoProviderImpl?

fabiorossetto avatar May 30 '23 14:05 fabiorossetto