Remove the per-client disconnect tracking from ProxyClientBase: client
objects no longer register a cleanup callback with their Connection, and a
disconnect no longer eagerly releases their m_client capability handles or
nulls their connection pointers.
Neither is necessary now that proxy objects share ownership of their
Connection. The connection pointer stays valid after a disconnect because the
Connection outlives its proxies, and keeping the capability handle is safe:
Cap'n Proto's per-connection state is refcounted and outlives the RPC system as
long as handles reference it, with calls on handles of a disconnected
connection failing cleanly with DISCONNECTED errors. The handle is simply
released (on the event loop thread, since capability refcounts are not thread
safe) whenever the client object is eventually destroyed, and clientInvoke
checks the connection's disconnected() predicate instead of a nulled pointer,
throwing the same 'IPC client method called after disconnect' error as before.
This deletes the detach machinery from ~ProxyClientBase, including the FIXME'd
duplicate-cleanup code path. Connection::onDisconnect (the renamed
addSyncCleanup) remains for its one other user, the per-thread connection maps
(see SetThread), which the next commit converts.
Because the connection pointer is no longer nulled on disconnect, ~ProxyClient
<Thread> can no longer use it to tell whether Connection::disconnect() has
already run and freed its m_disconnect_cb cleanup node. It now keys off the
connection's disconnected() predicate instead: if the connection is
disconnected the node is already gone and must not be passed to
cancelOnDisconnect. Without this, ~ProxyClient<Thread> erased an already-freed
list node -- a heap-use-after-free (see the "Waiting for in-flight server call
to finish after disconnect" test, which this commit re-enables).
That test also has to hold its own shared reference to the server Connection
across the disconnect() + waitDrained() sequence, the way Ipc::disconnect
Incoming does: under shared ownership the last server proxy (destroyed once the
drained body finishes) would otherwise free the Connection while the test is
still observing it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>