For socket programming, there are two basic structures to deal with addresses: struct sockaddr_in and sockaddr. According to man, "the only purpose of this structure [sockadrr] is to cast the structure pointer passed in addr in order to avoid compiler warnings" Every manual, snippet of code on books or programmer assumes whenever a function says it takes a struct sockaddr* you can cast your struct sockaddr_in* to that type with ease and safety.
Example from man bind
struct sockaddr_in myaddr;
int s;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(3490);
inet_aton("63.161.169.137", &myaddr.sin_addr.s_addr);
s = socket(PF_INET, SOCK_STREAM, 0);
bind(s, (struct sockaddr*)&myaddr, sizeof(myaddr));
The problem is this casting violates MISRA C 2008 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly.
What I want to know is, to overcome this problem (I am sure there is tons of people working with sockets and MISRA) is always necessary to justify the deviation of the rule? Is there actually no alternative to this casting?
Related question explaining what the casting to sockaddr is done:
Socket Programming, Casting sockaddr_in to sockaddr. Why?
casting between sockaddr and sockaddr_in
Typecasting sockaddr structures
CodePudding user response:
As told upon reading rule 5.2.7, the error comes from attempting a cast between incompatible types. It has nothing to do with C or C casts - using reinterpret_cast
would have been just as bad. You are simply doing a fishy conversion between two different structure types which is undefined behavior in C and C both.
It's been ages since I used Windows sockets but as far as I can tell sockaddr
isn't the slightest compatible with sockaddr_in
. I could be mistaken, but it would seem that the tool is simply saying "bug here" and the solution is to fix the bug?
Otherwise, if they are indeed equivalent in terms of memory layout, then in C you could have solved this by creating a union
of the two struct types, initialize one type and pass the other to the function, also known as "type punning". This isn't allowed in C though. Note that winsock was designed for C and not C .
The C solution would mean that you either have to memcpy
one struct instance into the other (rather fishy practice) or write some serialize/de-serialize routine (slow).
Or you could just use the actual type that the function asks for and all problems will go away...
CodePudding user response:
Example from man bind
myaddr.sin_family = AF_INET; myaddr.sin_port = htons(3490); inet_aton("63.161.169.137", &myaddr.sin_addr.s_addr); s = socket(PF_INET, SOCK_STREAM, 0); bind(s, (struct sockaddr*)&myaddr, sizeof(myaddr)); ``` The problem is this casting violates MISRA C 2008 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly.
Correct. You are casting a pointer to struct sockaddr_in
to a pointer to struct sockaddr
. Castering to an unrelated type is generally a Bad Thing.
If you really need to do this, then you need to raise a deviation, not just to document that you are doing it, but to detail the mitigations that you will perform to demonstrate that your code is fit to use.
CodePudding user response:
From my experience with that kind of code (in MISRA context, too): one just adds proper exception to the linter and goes on with it. That kind of need to cast is generally a design flaw in the socket API every programmer has stumbled upon and not much cannot be done to avoid it (if anything).
What can (and probably should) be done though is to limit the number of those casts and cast only when passing to socket specific API functions, never earlier; in turn, this shall lead to limiting the number of socket API calls by abstracting them away as a workaround. But still, the typecast cannot be avoided, only their number and scope can (and should) be limited.