Fix transport_conn_close fd double-close race

transport_conn_close previously called close(conn->fd), but the detached
read thread also calls close(conn->fd) when it exits.  If the kernel reused
the fd number before the read thread ran, the thread's close() would hit
the new connection — explaining connections that appeared to not terminate.

Fix: use shutdown(SHUT_RDWR) instead.  This signals EOF to the remote end
and unblocks the blocked read() without releasing the fd.  The read thread
remains the sole owner of the fd and is the only one to call close().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-29 19:54:55 +00:00
parent 835cbbafba
commit ae2cc51626

View File

@@ -319,5 +319,11 @@ struct App_Error transport_send_frame(struct Transport_Conn *conn,
} }
void transport_conn_close(struct Transport_Conn *conn) { void transport_conn_close(struct Transport_Conn *conn) {
close(conn->fd); /* shutdown() rather than close(): signals EOF to the remote end and
* unblocks the read thread without releasing the fd. The read thread
* is the sole owner of the fd and will close() it when it exits.
* Using close() here would create a race where the fd number could be
* reused by the next transport_connect() before the detached read
* thread calls its own close(), which would then close the wrong fd. */
shutdown(conn->fd, SHUT_RDWR);
} }