POSIX intends pointers to variations of struct sockaddr
to be castable, however depending on the interpretation of the C standard this may be a violation of the strict aliasing rule and therefore UB. (See this answer with comments below it.) I can, at least, confirm that there may at least be a problem with gcc: this code prints Bug!
with optimization enabled, and Yay!
with optimization disabled:
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
sa_family_t test(struct sockaddr *a, struct sockaddr_in *b)
{
a->sa_family = AF_UNSPEC;
b->sin_family = AF_INET;
return a->sa_family; // AF_INET please!
}
int main(void)
{
struct sockaddr addr;
sa_family_t x = test(&addr, (struct sockaddr_in*)&addr);
if(x == AF_INET)
printf("Yay!\n");
else if(x == AF_UNSPEC)
printf("Bug!\n");
return 0;
}
Observe this behavior on an online IDE.
To workaround this problem this answer proposes the use of type punning with unions:
/*! Multi-family socket end-point address. */
typedef union address
{
struct sockaddr sa;
struct sockaddr_in sa_in;
struct sockaddr_in6 sa_in6;
struct sockaddr_storage sa_stor;
}
address_t;
However, apparently things are still not as simple as they look… Quoting this comment by @zwol:
That can work but takes a fair bit of care. More than I can fit into this comment box.
What kind of fair bit of care does it take? What are the pitfalls of the use of type punning with unions to cast between variations of struct sockaddr
?
I prefer to ask than to run into UB.