Problem
`SingleInstance::~SingleInstance()` (src/core/services/single_instance.cpp:52-54) unconditionally `unlink()`s the socket path on destruction, even when this instance never bound/listened on it.
Sequence:
- First launch binds the socket and becomes primary.
- Second launch connects, sends RAISE, and exits — its `SingleInstance` object still had `socket_path_` set (computed by `get_socket_path()` regardless of role) but `server_fd_` stayed -1.
- Its destructor unlinks the socket file anyway, deleting the first instance's live listening socket from the filesystem.
- A third launch's `connect()` now fails (file gone) and it becomes a second primary — single-instance is silently broken after any second launch.
Secondary issue
`listen_thread()` does a blocking `read()` on every accepted connection with no timeout. A client that connects but never writes (or never closes) wedges the listener thread; `~SingleInstance()`'s `join()` would then hang.
Fix
- Track whether this object successfully bound+listened (e.g. `bool owns_socket_`); only unlink if true.
- Bound the per-connection read (timeout via `SO_RCVTIMEO` or a poll/select with timeout) so a silent/malicious-ish client can't wedge the thread.
Found via code-review of user feedback after real-world macOS usage.
Problem
`SingleInstance::~SingleInstance()` (src/core/services/single_instance.cpp:52-54) unconditionally `unlink()`s the socket path on destruction, even when this instance never bound/listened on it.
Sequence:
Secondary issue
`listen_thread()` does a blocking `read()` on every accepted connection with no timeout. A client that connects but never writes (or never closes) wedges the listener thread; `~SingleInstance()`'s `join()` would then hang.
Fix
Found via code-review of user feedback after real-world macOS usage.