2

On this page regarding a certain Winsock struct, the example appears to be taking the address of a struct and casting the resulting pointer to a pointer to a completely different struct.

SOCKET ListenSocket;
struct sockaddr_in saServer;
// Bind the listening socket using the information in the sockaddr structure
bind( ListenSocket,(SOCKADDR*) &saServer, sizeof(saServer) );

Here are the declarations for the two structs. This is technically undefined behavior, correct?

struct sockaddr {
        ushort  sa_family;
        char    sa_data[14];
};

struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};
ThomasMcLeod
  • 7,603
  • 4
  • 42
  • 80
  • Pointer casts never violate the strict aliasing rule (seems this is a common misconception) – M.M Jun 29 '17 at 03:47
  • 1
    @M.M, but surely the implementation of `bind` is going to have to deference that pointer, and at *that* point you're violating the strict aliasing rule, no? (I have the vague impression that you may be saved by the fact that the only element of the structure being read via the alias is at the beginning of the struct and is common to both, but it isn't at all obvious to me that this is true from a language-lawyer perspective.) – Harry Johnston Jun 29 '17 at 04:03
  • @HarryJohnston library implementations aren't subject to ISO C++ rules, they might not even be written in C++ – M.M Jun 29 '17 at 04:21
  • @M.M, fair enough; that resolves the issue in this particular context. I guess that if you were implementing `bind` yourself you could make it safe by explicitly casting the pointer to `short` [as discussed here](https://stackoverflow.com/a/9747062/886887). I'm not sure that's necessary, but it should be sufficient. – Harry Johnston Jun 29 '17 at 04:51

1 Answers1

3

Between the dawn of C (going back at least to 1974) and 1989, if two structures shared a Common Initial Sequence, the language unambiguously allowed code to use a pointer of one structure type to inspect CIS members of the other. In the C99 standard, that permission was restricted to cases where both structure types are part of a union type whose complete declaration was visible at the point where the CIS value is inspected; some people insist that because the authors of the 1989 meant to impose such a restriction it applies to C89 as well. In addition, some compiler writers insist that because the authors of the Standard only meant for that guarantee to apply to accesses made through lvalues of union type, they'll ignore the part of the Standard that says that a definition of a "complete union type" must be visible.

Implementations are allowed to provide guarantees beyond those required by the Standard. Because non-psychic people writing code prior to C99 had no reason to expect that they would need to include otherwise-unnecessary union declarations in order to exploit the CIS guarantees, and because a lot of code written from that era relies upon those guarantees despite a lack of such declarations, anyone wanting to write an implementation suitable for use with such code must support them whether or not the Standard requires such support. While there is no particularly good reason why updates to the header file shouldn't include a union type declaration, I'm not sure how many compilers would care about its presence or absence. The compilers I've seen either support the CIS guarantees even without a complete union type declaration visible, or dishonor the CIS guarantees (ignoring the Standard) even when the declaration is present.

supercat
  • 77,689
  • 9
  • 166
  • 211