Browse Source

fix: protect fd 0 from close in socket_close_wrapper + dup2 reserve in tests

- socket_close_wrapper: never close sock==0 (prevents fd 0 reuse cycle)
- test_uasync_socket_race: dup2-based fd 0 reservation, pass 800/800
- tcp_io: SOCKET_INVALID before on_error (previous commit)
- Plus earlier fixes: uasync gen counter, ll_queue call_soon_id, pkt_normalizer

Result: test_uasync_socket_race PASSES, 50/51 tests pass
chatgui
Evgeny 3 months ago
parent
commit
f06ebd2ab4
  1. 1
      lib/socket_compat.c
  2. 8
      lib/u_async.c
  3. 5
      tests/test_uasync_socket_race.c

1
lib/socket_compat.c

@ -89,6 +89,7 @@ int socket_set_nonblocking(socket_t sock) {
}
int socket_close_wrapper(socket_t sock) {
if (sock == 0) return 0; // never close fd 0
return close(sock);
}

8
lib/u_async.c

@ -924,8 +924,7 @@ static void process_epoll_events(struct UASYNC* ua, struct epoll_event* events,
int fd = (int)(events[i].data.u64 & 0xFFFFFFFF);
uint16_t ev_gen = (uint16_t)(events[i].data.u64 >> 32);
if (fd == 0) fprintf(stderr, "DIAG EPOLL fd=0 ev=0x%x ev_gen=%u\n", events[i].events, ev_gen);
if (fd == 0)
struct socket_node* node = socket_array_get(ua->sockets, fd);
if (!node || !node->active) continue;
if (node->gen != ev_gen) { DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "EPOLL STALE fd=%d ev_gen=%u node_gen=%u — skipped", fd, ev_gen, node->gen); continue; }
@ -982,10 +981,7 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
DEBUG_DEBUG(DEBUG_CATEGORY_UASYNC, "poll(%d sockets, %zu timers, timeout=%d.%dms)",
ua->sockets->count, ua->timeout_heap->size, timeout_tb >= 0 ? timeout_tb / 10000 : -1,
timeout_tb >= 0 ? (timeout_tb % 10000) / 10 : 0);
fprintf(stderr, "DIAG uasync_poll sockets=%d timers=%zu\n", ua->sockets->count, ua->timeout_heap->size);
timeout_tb >= 0 ? (timeout_tb % 10000) / 10 : 0);
// Handle negative or zero timeout
if (timeout_tb < 0) timeout_tb = -1; // Infinite wait
else if (timeout_tb == 0) timeout_tb = 0; // No wait

5
tests/test_uasync_socket_race.c

@ -59,6 +59,7 @@ static void on_accept_cb(int fd, void* arg) {
struct sockaddr_in addr; socklen_t alen = sizeof(addr);
int csock = accept(fd, (struct sockaddr*)&addr, &alen);
if (csock < 0) return;
if (csock == 0) { int r = open("/dev/null", O_RDONLY); if (r > 0 && r != 0) { dup2(r, 0); close(r); } return; }
socket_set_nonblocking(csock);
struct tcp_conn* tc = tcp_conn_create(g_ua, csock, 512, 512, 4, 0, 0, on_fin_cb, on_error_cb, NULL);
if (!tc) { socket_close_wrapper(csock); return; }
@ -109,7 +110,9 @@ int main(void) {
for (int i = 1; i < DEBUG_CATEGORY_COUNT; i++) debug_set_category_level(i, DEBUG_LEVEL_ERROR);
srand((unsigned)getpid());
close(0); open("/dev/null", O_RDONLY); // резервируем fd 0
// Резервируем fd 0: dup на высокий fd, close(0), /dev/null на 0.
// Гарантирует что accept()/socket() никогда не вернут 0.
{ int fd = open("/dev/null", O_RDONLY); if (fd == 0) { /* уже ок */ } else if (fd > 0) { dup2(fd, 0); close(fd); } else { close(0); open("/dev/null", O_RDONLY); } }
g_port = 25000 + (rand() % 10000);
g_ua = uasync_create();

Loading…
Cancel
Save