From 75d638ac9cc613f39ec4513d3dc2e43a6f909da1 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Sun, 30 Aug 2026 12:58:43 +0200 Subject: fix(udp): receive(0) tests and bad call to getnameinfo --- src/udp.c | 12 ++++++++++++ src/wsocket.c | 8 ++++++++ 2 files changed, 20 insertions(+) (limited to 'src') diff --git a/src/udp.c b/src/udp.c index 712ad50..a782699 100644 --- a/src/udp.c +++ b/src/udp.c @@ -277,6 +277,7 @@ static int meth_receivefrom(lua_State *L) { lua_pushliteral(L, "out of memory"); return 2; } + memset(&addr, 0, sizeof(addr)); err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, &addr_len, tm); /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ @@ -286,6 +287,17 @@ static int meth_receivefrom(lua_State *L) { if (wanted > sizeof(buf)) free(dgram); return 2; } + /* a zero-length request may be satisfied by some kernels (notably + * Darwin/BSD) without ever touching the sender's address -- only + * resolve it when the OS actually reported one, instead of feeding + * getnameinfo() a garbage/zeroed sockaddr. */ + if (addr.ss_family != AF_INET && addr.ss_family != AF_INET6) { + lua_pushlstring(L, dgram, got); + lua_pushnil(L); + lua_pushnil(L); + if (wanted > sizeof(buf)) free(dgram); + return 3; + } err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); if (err) { diff --git a/src/wsocket.c b/src/wsocket.c index 86c6994..b2b668c 100644 --- a/src/wsocket.c +++ b/src/wsocket.c @@ -286,6 +286,14 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, } if (taken == 0) return IO_CLOSED; err = WSAGetLastError(); + /* a zero-length request is trivially "too small" for any + * non-empty datagram; unlike POSIX, which truncates and succeeds + * silently, Windows reports this as WSAEMSGSIZE even though the + * datagram -- and its sender's address, already written to addr/ + * len above -- was still consumed. Normalize it to match POSIX's + * silent-truncation instead of surfacing a platform-specific + * error for what is otherwise a successful, if empty, receive. */ + if (count == 0 && err == WSAEMSGSIZE) return IO_DONE; /* On UDP, a connreset simply means the previous send failed. * So we try again. * On TCP, it means our socket is now useless, so the error passes. -- cgit v1.2.3-55-g6feb