views:

68

answers:

3

I've got code that looks something like this, where addr is a sockaddr*:

struct sockaddr_in *sin = (struct sockaddr_in *) addr;
const char *IP=inet_ntoa(sin -> sin_addr);

I believe this is very typical code for using Berkeley sockets.

However, when I compile this, I'm getting the following warning:
dereferencing pointer 'sin' does break strict anti-aliasing rules

Searching online, I find some discussion of the fact that the way I'm doing things is pretty typical, but this compiler warning also is pretty real and not a good thing.

What's the proper way to redo this code to fix the warning, and not just silence it?

A: 

If your header file and your compiler are both parts of the same C or C++ implementation, complain to your vendor and ask them to put a suitable #pragma in their header file to silence their compiler. As implementor, they're allowed to play games like that, as long as they provide a conforming implementation.

If your header file and your compiler came from two separate C or C++ implementations, you're lucky that things work as well as they do, and you have to solve it yourself.

Windows programmer
Sockets are not part of a compiler implementation but part of the operating system.
Jens Gustedt
Where the programmer has "#include <something.h>", either that header file something.h is part of a C or C++ implementation, or else the programmer is lucky that things work as well as they do and the programmer has to solve it theirself.
Windows programmer
+1  A: 

Depending on how you've used struct sockaddr, I think either your code is broken, or gcc is broken. struct sockaddr and struct sockaddr_in have a common initial element (sa_family/sin_family) so it does not violate aliasing rules if you have accessed only this element through both pointers; doing so is permitted by C99. Moreover, struct sockaddr has no other elements you're allowed to access. It's largely an opaque type for primitive socket address polymorphism. If you have been poking around at implementation-specific internals in struct sockaddr, or worse yet, if you declared a struct sockaddr object rather than just a pointer or performed copying between such objects, your code is broken. If you didn't, and gcc is giving a warning claiming you've broken aliasing rules, then gcc's warning generation is broken. I surely wouldn't be surprised if it's the latter.

R..
@R. first I don't think that it is stated that `sa_family/sin_family` is a common initial element. They must be present both, with identical values. Then the access as the OP gave it *is* a violation of aliasing rules, basically he is doing `((struct sockaddr_in *)addr)->sin_addr` which is a common idiom to do such things.
Jens Gustedt
Casting a pointer and then dereferencing it is, by itself, **never** a violation of aliasing rules. Only if you also dereferenced it though the original type can aliasing rules have been violated. Regardless of whether POSIX guarantees that `*_family` is a common initial element, in practice it **is**, and gcc, having the structure definition, knows this. So my claim about no aliasing rules having been violated is correct.
R..
A: 

Yes, this is a know problem with gcc and sockets. The problem basically seems to be that the way this ip[46] stuff is designed is incompatible with the assumptions that the gcc people think they can deduce about aliasing of pointers.

I usually get away with this by first taking a pointer on the struct

struct in_addr* act = &(sin->sin_addr);

and then using *act.

Jens Gustedt
If gcc doesn't give you the same warning when you use *act, either you didn't enable the same warnings that the original poster did, or you found a bug in gcc.
Windows programmer