Hello,

I'm observing the following strange behavior, where
trying to bind(2) a socket on "::1" fails with
EADDRNOTAVAIL, but binding in6addr_any will succeed
(and then yield a bound ::1).  What's more, the
behavior is inconsistent depending on the compiler
used.

Here's my sample program a.c:

----
#include <arpa/inet.h>
#include <sys/socket.h>

#include <netinet/in.h>

#include <err.h>
#include <stdlib.h>

#define PORT 12345

int
main(int argc, char **argv) {
        int sock;
        socklen_t a, b;
        struct sockaddr_storage server;
        struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&server;

        if ((sock = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
                err(EXIT_FAILURE, "socket");
                /* NOTREACHED */
        }

        if (inet_pton(PF_INET6, "::1", &(sin->sin6_addr)) != 1) {
                err(EXIT_FAILURE, "inet_pton");
                /* NOTREACHED */
        }

        sin->sin6_family = PF_INET6;
        sin->sin6_port = htons(PORT);

        if (bind(sock, (struct sockaddr *)sin, sizeof(*sin)) != 0) {
                err(EXIT_FAILURE, "bind");
                /* NOTREACHED */
        }

        return 0;
}
----

This program succeeds in binding and returns 0, as
expected.  However, note the declaration of the unused
socklen_t a and b.  If I remove that declaration, the
call to bind(2) will fail:

$ diff -bu [ab].c
--- a.c 2021-11-23 19:49:05.926884000 +0000
+++ b.c 2021-11-23 19:48:51.409173000 +0000
@@ -11,7 +11,6 @@
 int
 main(int argc, char **argv) {
        int sock;
-       socklen_t a, b;
        struct sockaddr_storage server;
        struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&server;
 
$ ./a.out
$ echo $?
0
$ cc b.c
$ ./a.out
a.out: bind: Can't assign requested address
$ 

This is on FreeBSD 13.0-RELEASE with FreeBSD clang
version 11.0.1.

Compiling either with gcc version 10.3.0 fails.


So my questions are:

- Why does _any_ of those fail?
- Why does a.c succeed when compiled with clang, but
  b.c does not?

-Jan

Reply via email to