I'm writing some socket code and based on some params I'm using either IPv4 or IPv6. For that I have a code like this:
struct sockaddr final_addr;
...
struct sockaddr_in6 addr6;
...
memcpy(&final_addr, &addr6, size);
...
bind(fd, &final_addr, size);
This works fine. However if I do (which was my initial idea)
struct sockaddr final_addr;
...
struct sockaddr_in6 addr6;
...
final_addr = *reinterpret_cast<struct sockaddr*>(&addr6);
...
bind(fd, &final_addr, size);
then it fails on bind
with Cannot assign requested address
error.
Note that this incorrect code works fine if I switch to IPv4's sockaddr_in
.
What's going on here? Why can't I just reinterpret sockaddr_in6
as sockaddr
?
If in the first version of the code size
is sizeof(addr6)
(as you stated in the comments), then the first version of the code uses memcpy
to copy sizeof(struct sockaddr_in6)
bytes of data.
The second version of the code uses regular struct sockaddr
assignment to copy only sizeof(struct sockaddr)
bytes.
sizeof(struct sockaddr)
is smaller than sizeof(struct sockaddr_in6)
, which makes these two code samples different.
Note that in the first version the recipient object in that memcpy
is of struct sockaddr
type, i.e. it is smaller than the number of bytes copied. Memory overrun occurs, which clobbers some other data stored in adjacent memory locations. The code "works" only by accident. I.e. if this bit "works", then some other piece of code (the one that relies on the now-clobbered data) is likely to fail.