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:
1 parent
aff3b2d00f
commit
a97a38d867
3 files changed
+627
-622
No files matched your search
+1
-2
@@ -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
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user