IN6_IS_ADDR_* macros use invalid type punning?
Matthias Andree
mandree at FreeBSD.org
Thu Jun 6 20:23:32 UTC 2013
-- NOTE -- Please Cc: me on replies, I am not subscribed to freebsd-net.
Greetings,
I am just staring at gcc 4.8 warnings when compiling the try.c code
shown below:
----------------------------------------------------------------
$ cat try.c
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
int f(void) {
struct sockaddr_in6 sin6;
int r = IN6_IS_ADDR_V4MAPPED((&sin6.sin6_addr));
return r;
}
----------------------------------------------------------------
----------------------------------------------------------------
$ gcc48 -Wall -O2 -c try.c
try.c: In function 'f':
try.c:9:5: warning: dereferencing type-punned pointer will break
strict-aliasing rules [-Wstrict-aliasing]
int r = IN6_IS_ADDR_V4MAPPED((&sin6.sin6_addr));
^
try.c:9:5: warning: dereferencing type-punned pointer will break
strict-aliasing rules [-Wstrict-aliasing]
try.c:9:5: warning: dereferencing type-punned pointer will break
strict-aliasing rules [-Wstrict-aliasing]
----------------------------------------------------------------
This is on FreeBSD 9.1-RELEASE amd64.
/usr/include/netinet6/in6.h contains:
/*
* Mapped
*/
#define IN6_IS_ADDR_V4MAPPED(a) \
((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
(*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
(*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) ==
ntohl(0x0000ffff)))
So we indeed break C99/C11 aliasing rules here.
Pedantically speaking, it would also have to be htonl() instead of
ntohl() because the in6_addr is in network order, but it does not matter
to the machine because either maps to __bswap32() anyway.
The same in6.h also declares:
struct in6_addr {
union {
uint8_t __u6_addr8[16];
uint16_t __u6_addr16[8];
uint32_t __u6_addr32[4];
} __u6_addr; /* 128-bit IP6 address */
};
Which would appear to open up an alias-safe way (sanctioned by the C
standard, access through union containing the type) to reimplement the
macro, which also makes the GCC 4.8 warning go away and is far more
readable:
/*
* Mapped
*/
#define IN6_IS_ADDR_V4MAPPED(a) \
((a)->__u6_addr.__u6_addr32[0] == 0 && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr16[2] == htonl(0x0000ffff))
Similar considerations apply to the other IN6_IS_ADDR_* macros.
Now, what do we do?
Can we get these fixed in a reasonable timeframe?
To whom, or where, would I submit a patch for all the macros so that it
actually gets committed to HEAD and MFC'd to /9 and /8?
Do we have unit tests for these macros? Should we add some?
Best
Matthias
(I don't have src commit permission.)
-- NOTE -- Please Cc: me on replies, I am not subscribed to freebsd-net.
More information about the freebsd-net
mailing list