In case of an error and early exit we don't reach the end of the main() function, where we used to disconnect the remote executor explicitly. During disconnect we join the ListenerThread in RemoteTargetProcessControl. This won't happen in case of an error right now.
With this patch the destructor of RemoteTargetProcessControl attempts to disconnect as well. The new atomic flag AttemptDisconnect makes sure we only do this once.
I agree that this is a bit of a design issue, but it's not straightforward to fix. IMHO the conceptual goal in LLJITWithRemoteDebugging.cpp is valid:
Also, I think it makes sense to report RPC-related errors via ExecutionSession. The current LLJIT interface requires to hand over ownership of the ExecutionSession to the JIT and once it goes out of scope it gets deleted. This causes the dangling reference in the OrcRPCTargetProcessControlBase's ErrorReporter unique_function, which is really bad yes. This is why we need to avoid reportError() in the destructor here.
What is the proper solution? I could imagine LLJIT could only "borrow" ownership of the ExecutionSession. It requires a mechanism to hand it back upon destruction.