Fixes #378
There are 2 issues with non-libmultiprocess clients:
- After a
destroy(), any request can still be sent as long as the capability is not dropped. Such request dereferenced a nullm_implpointer (reset by the previousdestroy()call) and crashed the server (also reported in bitcoin/bitcoin#36502). - Sending
destroy()while another request on the same object was running could freem_implwhile that request was still using it.
The libmultiprocess C++ client cannot trigger either case because it sends destroy() only from the ProxyClient destructor and releases the capability after that.
This PR implements the fixes suggested in the issue.
serverInvokechecksm_destroyedand rejects requests received afterdestroy()with "method called after destroy".invokeDestroychecksm_active_callsand rejectsdestroy()with "destroy called while other calls are in progress" when another request on the object is being executed.
Differences from the suggestion:
- No mutex is needed because
m_active_callsandm_destroyedare accessed only from the event-loop thread. - Only requests with an
mp.Contextare counted inm_active_calls. Requests without one run to completion on the event-loop thread, sodestroy()cannot run during their execution.
Also added a regression test that manually builds and sends requests with Cap'n Proto, reproducing the behavior of a buggy non-libmultiprocess client.