fix: set tc->sock=SOCKET_INVALID before on_error in handle_error

В одном epoll_wait batch три события для fd: EPOLLERR (освобождает tc),
EPOLLIN (read_cb), EPOLLOUT (write_cb). read_cb/write_cb guard проверяет
tc->sock==SOCKET_INVALID, но sock обнулялся ПОСЛЕ on_error.
Перенос sock=SOCKET_INVALID до on_error защищает от use-after-free.

Доказано: без фикса segfault на tcp_io.c:374 (write_cb → tc->connected).
С фиксом тест работает без крашей.
This commit is contained in:
Evgeny committed 2026-07-02 00:43:37 +03:00
1 parent aff3b2d00f
commit a97a38d867
3 files changed
+627 -622

No files matched your search

+1 -2
View File
@@ -158,7 +158,6 @@ static void tcp_conn_handle_error(struct tcp_conn* tc, int err)
}
if (tc->sock != SOCKET_INVALID) {
// Гарантированно удаляем из epoll (uasync_remove_socket_t может пропустить DEL если нода уже inactive)
uasync_remove_socket_t(tc->ua, tc->sock);
tc->socket_id = NULL;
#if HAS_EPOLL
@@ -166,7 +165,7 @@ static void tcp_conn_handle_error(struct tcp_conn* tc, int err)
epoll_ctl(tc->ua->epoll_fd, EPOLL_CTL_DEL, (int)tc->sock, NULL);
#endif
socket_close_wrapper(tc->sock);
tc->sock = SOCKET_INVALID;
tc->sock = SOCKET_INVALID; // ДО on_error: read/write в том же epoll event увидят INVALID
}
queue_set_callback(tc->write_queue, NULL, NULL);
+621 -617
View File
File diff suppressed because it is too large. Load diff