[Bug 295009] UDP receive with zero-size buffer immediately returns, no wait, no EAGAIN

From: <bugzilla-noreply_at_freebsd.org>
Date: Mon, 04 May 2026 15:45:22 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=295009

            Bug ID: 295009
           Summary: UDP receive with zero-size buffer immediately returns,
                    no wait, no EAGAIN
           Product: Base System
           Version: 15.0-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Many People
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: thierry@lelegard.fr

On FreeBSD 15.0-RELEASE-p8, receiving a UDP datagram using recv(), recvfrom(),
or recvmsg() with a zero-size data buffer immediately returns with value zero,
even when no datagram is sent, even when the socket is in non-blocking mode.

According to the POSIX spec and the FreeBSD man pages, when zero is specified
as reception buffer size, the correct behaviour should be:

- In blocking mode: wait for a datagram, return zero, optionally report the
  truncation of the message in flags.
- In non-blocking mode, when no message is immediately available, return -1
  and set errno to EAGAIN.

Other operating systems:

- macOS 26.4.1 behaves as FreeBSD. The bug is probably in their common roots.
- Linux 7.0: expected POSIX behaviour.

The following code reproduces the problem. It opens a UDP socket, binds it to
127.0.0.1:1234, and receives a message (typically a text string to display).

There are two parameters: receive buffer size and optional non-blocking mode.

Syntax: udpzero [bufsize [-n]]
  bufsize : receive buffer size, default: 256
  -n : non-blocking

Sample command to send a 4-byte message using bash:
echo -n "abcd" >/dev/udp/127.0.0.1/1234

On FreeBSD 15.0-RELEASE-p8 and macOS 26.4.1:

$ ./udpzero
receive buffer size: 256, blocking mode
    [... wait for a message ...]
received size: 4, data: "abcd"
$
$ ./udpzero 10 -n
receive buffer size: 10, non-blocking mode
recv: Resource temporarily unavailable
$
$ ./udpzero 0
receive buffer size: 0, blocking mode
received size: 0, data: ""
$
$ ./udpzero 0 -n
receive buffer size: 0, non-blocking mode
received size: 0, data: ""

On Linux 7.0 (Ubuntu 26.04):

$ ./udpzero
receive buffer size: 256, blocking mode
    [... wait for a message ...]
received size: 4, data: "abcd"
$
$ ./udpzero 10 -n
receive buffer size: 10, non-blocking mode
recv: Resource temporarily unavailable
$
$ ./udpzero 0
receive buffer size: 0, blocking mode
    [... wait for a message ...]
received size: 0, data: ""
$
$ ./udpzero 0 -n
receive buffer size: 0, non-blocking mode
recv: Resource temporarily unavailable

-----------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

void check(int cond, const char* message)
{
    if (!cond) {
        perror(message);
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char* argv[])
{
    const int bufsize = argc < 2 ? 256 : atoi(argv[1]);
    const int nonblock = argc >= 3 && strcmp(argv[2], "-n") == 0;
    printf("receive buffer size: %d, %sblocking mode\n", bufsize, nonblock ?
"non-" : "");

    char* data = malloc(bufsize);
    check(data != NULL, "malloc");

    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    check(sock >= 0, "socket");

    if (nonblock) {
        int flags = fcntl(sock, F_GETFL, 0);
        check(flags != -1, "fcntl");
        flags = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
        check(flags != -1, "fcntl");
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(0x7F000001); // 127.0.0.1
    addr.sin_port = htons(1234);
    int status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
    check(status == 0, "bind");

    socklen_t len = sizeof(addr);
    ssize_t insize = recvfrom(sock, data, bufsize, 0, (struct sockaddr*)&addr,
&len);
    check(insize >= 0, "recv");
    printf("received size: %ld, data: \"%.*s\"\n", insize, (int)insize, data);

    close(sock);
    return EXIT_SUCCESS;
}

-- 
You are receiving this mail because:
You are the assignee for the bug.