From aff3b2d00faa6e94719d30615da85d8d02cd9bf4 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Thu, 2 Jul 2026 00:16:05 +0300 Subject: [PATCH] fix: always remove socket from epoll in tcp_conn_handle_error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcp_conn_handle_error гвардил uasync_remove_socket_t по tc->socket_id, пропуская повторный вызов. В одном epoll_wait batch два события (EPOLLERR + EPOLLOUT) на один fd: первое делает remove (socket_id=NULL), второе проходит guard и dispatch'ит write_cb на освобождённом tc. Фикс: всегда вызывать uasync_remove_socket_t + epoll_ctl(DEL), независимо от socket_id. --- lib/tcp_io.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/tcp_io.c b/lib/tcp_io.c index 8e3918ff..effe2651 100644 --- a/lib/tcp_io.c +++ b/lib/tcp_io.c @@ -32,7 +32,7 @@ struct tcp_conn* tcp_conn_create( void (*on_error)(struct tcp_conn* tc, int err, void* arg), void* arg) { - if (!ua || sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "tcp_conn_create: invalid args ua=%p", ua); return NULL; } + if (!ua || sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "tcp_conn_create: invalid args ua=%p", (void*)ua); return NULL; } struct tcp_conn* tc = u_calloc(1, sizeof(struct tcp_conn)); if (!tc) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "tcp_conn_create: u_calloc failed"); return NULL; } @@ -157,11 +157,14 @@ static void tcp_conn_handle_error(struct tcp_conn* tc, int err) } } - if (tc->socket_id) { + 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 (tc->sock != SOCKET_INVALID) { +#if HAS_EPOLL + if (tc->ua && tc->ua->use_epoll && tc->ua->epoll_fd >= 0) + epoll_ctl(tc->ua->epoll_fd, EPOLL_CTL_DEL, (int)tc->sock, NULL); +#endif socket_close_wrapper(tc->sock); tc->sock = SOCKET_INVALID; }