I wrote in <https://lists.gnu.org/archive/html/bug-gnulib/2020-12/msg00077.html> and <https://lists.gnu.org/archive/html/bug-gnulib/2021-01/msg00053.html>: > > On FreeBSD 12.0 — but not on FreeBSD 11.0 and 12.2 —, I'm seeing a test > > failure of the Gnulib 'passfd' test: > > > > recvfd: Permission denied > > FAIL test-passfd (exit status: 16) > > Likewise on FreeBSD 12.1.1 and NetBSD 9.0.
I looked on which platforms the test fails: OS version bitness compiler result freebsd 11 32 clang 3.8 OK freebsd 11 64 clang 3.8 OK freebsd/arm64 11 64 clang 4.0.0 OK freebsd 12 32 clang 6.0.1 OK freebsd 12 64 clang 6.0.1 FAIL freebsd/arm64 12 64 clang 10.0.1 FAIL freebsd/sparc64 12 64 gcc 4.2.1 FAIL midnightbsd 2.0 32 gcc 7.4 OK midnightbsd 2.0 32 clang 8.0.1 OK midnightbsd 2.0 64 gcc 7.4 FAIL midnightbsd 2.0 64 clang 8.0.1 FAIL netbsd 8 32 gcc 5.5 OK netbsd 8 64 gcc 5.5 FAIL netbsd/sparc64 8 64 gcc 5.5 FAIL netbsd 9 64 gcc 7.4 FAIL openbsd 6.0 32 gcc 4.2.1 OK openbsd 6.0 64 gcc 4.2.1 OK openbsd 6.5 64 gcc 4.2.1 OK openbsd 6.5 64 clang 7.0.1 OK Result: * FAILs only in 64-bit mode, never in 32-bit mode * Only certain OSes (not OpenBSD) * Only certain OS versions (FreeBSD >= 11) * Independent of clang vs. gcc It smells like a wrongly computed alignment or buffer size. And indeed, this patch fixes it: 2021-02-16 Bruno Haible <br...@clisp.org> passfd: Fix test failure on FreeBSD >= 12 and NetBSD in 64-bit mode. * lib/passfd.c (recvfd): Use the CMSG_SPACE macro to compute the value for msg_controllen. diff --git a/lib/passfd.c b/lib/passfd.c index ca10ba5..a993f39 100644 --- a/lib/passfd.c +++ b/lib/passfd.c @@ -142,19 +142,23 @@ recvfd (int sock, int flags) cmsg->cmsg_len = CMSG_LEN (sizeof fd); /* Initialize the payload: */ memcpy (CMSG_DATA (cmsg), &fd, sizeof fd); - msg.msg_controllen = cmsg->cmsg_len; + msg.msg_controllen = CMSG_SPACE (sizeof fd); len = recvmsg (sock, &msg, flags_recvmsg); if (len < 0) return -1; - + if (len == 0) + { + /* fake errno: at end the file is not available */ + errno = ENOTCONN; + return -1; + } cmsg = CMSG_FIRSTHDR (&msg); /* be paranoiac */ - if (len == 0 || cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd) + if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { - /* fake errno: at end the file is not available */ - errno = len ? EACCES : ENOTCONN; + errno = EACCES; return -1; }