kernel/net: free TCP sockets closed before the handshake completes (#620)
Build system / Build (en_US) (push) Successful in 3m21s
Build system / Build (es_ES) (push) Successful in 3m23s
Build system / Build (ru_RU) (push) Successful in 1m37s
Build system / Publish Images (push) Successful in 2m16s

Summary: socket_close() skipped both tcp_disconnect and socket_free for any
TCP socket that was not yet in the SS_ISCONNECTED state, leaking the socket
structure and leaving it on the net_sockets list forever.

Details:
The SS_ISCONNECTED gate in socket_close covered only fully established
connections. A socket closed while in SYN_SENT, SYN_RECEIVED or LISTEN, or
one that never connected at all, fell through to a bare `ret`: it was
neither disconnected nor freed. The 4 KiB socket structure and its two ring
buffers stayed allocated, the socket kept its place on net_sockets, its
timers kept being decremented by tcp_timer_640ms, and SOCKET.TID kept
pointing at a thread that was about to exit. A browser or any other
application that opens connections which fail to establish (refused,
filtered, or simply cancelled by the user) leaked one socket per attempt.

The gate is not needed: tcp_disconnect dispatches on the TCB state itself
and jumps straight to tcp_close -- which calls socket_free -- whenever
t_state is below TCPS_ESTABLISHED. Dropping the test therefore routes the
not-yet-synchronized cases to exactly the cleanup they were missing, and
leaves the established path untouched. The SS_ISDISCONNECTING test is kept,
so a second close() on a socket already shutting down is still a no-op.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #620
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
This commit was merged in pull request #620.
This commit is contained in:
2026-08-03 18:08:29 +00:00
co-authored by Claude Opus 5
parent 2db92868a9
commit 8766bfc546
-2
View File
@@ -780,8 +780,6 @@ socket_close:
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .free
test [eax + SOCKET.state], SS_ISCONNECTED
jz @f
test [eax + SOCKET.state], SS_ISDISCONNECTING
jnz @f
call tcp_disconnect