The compiler produces this warning when I'm working with some code which looks like -
....
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
....
}
where p = res are of type struct addrinfo and the types producing warnings are sockaddr_in and sockaddr_in6. The warning comes from statements :
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
All I want to know is what is causing this warning and what can I do to correct it if this is not the proper way to do things. Could I use any of static_cast / dynamic_cast / reinterpret_cast here?
The exact warning is - cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4.
TLDR: This warning doesn't indicate an error in your code, but you can avoid it by using a poper c++ reinterpret_cast (thanks to #Kurt Stutsman).
Explanation:
Reason for the warning:
sockaddr consists of a unsigned short (usually 16 bit) and a char array, so its alignment requirement is 2.
sockaddr_in contains (among other things) a struct in_addr which has an alignment requirement of 4 which in turn means sockaddr_in also must be aligned to a 4 Byte boundary.
For that reason, casting an arbitrary sockaddr* to an sockaddr_in* changes the alignment requirement, and accessing the object via the new pointer would even violate aliasing rules and result in undefined behavior.
Why you can ignore it:
In your case, the object, p->ai_addr is pointing to, most likely is a sockaddr_in or sockaddr_in6 object anyway (as determined by checking ai_family) and so the operation is safe. However you compiler doesn't know that and produces a warning.
It is essentially the same thing as using a static_cast to cast a pointer to a base class to a pointer to a derived class - it is unsafe in the general case, but if you know the correct dynamic type extrinsically, it is well defined.
Solution:
I don't know a clean way around this (other than suppress the warning), which is not unusual with warnings enabled by -Weverything . You could copy the object pointed to by p->ai_addr byte by byte to an object of the appropriate type, but then you could (most likely) no longer use addr the same way as before, as it would now point to a different (e.g. local) variable.
-Weverything isn't something I would use for my usual builds anyway, because it adds far too much noise, but if you want to keep it, #Kurt Stutsman mentioned a good solution in the comments:
clang++ (g++ doesn't emit a warning in any case) doesn't emit a warning, if you use a reinterpret_cast instead of the c style cast (which you shouldn't use anyway), although both have (in this case) exactly the same functionality. Maybe because reinterpret_cast explicitly tells the compiler: "Trust me, I know, what I'm doing" .
On a side Note: In c++ code you don't need the struct keywords.
Well -Weverything enables quite a lot of warnings some of them are known to throw unwanted warnings.
Here your code fires the cast-align warning, that says explicitely
cast from ... to ... increases required alignment from ... to ...
And it is the case here because the alignement for struct addr is only 2 whereas it is 4 for struct addr_in.
But you (and the programmer for getaddrinfo...) know that the pointer p->ai_addr already points to an actual struct addr_in, so the cast is valid.
You can either:
let the warning fire and ignore it - after all it is just a warning...
silence it with -Wno-cast-align after -Weverything
I must admit that I seldom use -Weverything for that reason, and only use -Wall
Alternatively, if you know that you only use CLang, you can use pragmas to explicetely turn the warning only on those lines:
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
#pragma clang diagnostic pop
....
}
To elaborate on the memcpy version. I thnk this is needed for ARM which cannot have misalligned data.
I created a struct that contains just the first two fields (I only needed port)
struct sockaddr_in_header {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
};
Then to get the port out, I used memcpy to move the data to the stack
struct sockaddr_in_header sinh;
unsigned short sin_port;
memcpy(&sinh, conn->local_sockaddr, sizeof(struct sockaddr_in_header));
And return the port
sin_port = ntohs(sinh.sin_port);
This answer is really related to getting the port on Arm
How do I cast sockaddr pointer to sockaddr_in on Arm
The powers that be think that to be the same question as this one, however I dont want to ignore warnings. Experience has taught me that is a bad idea.
Related
I checked the git log as https://patchwork.sourceware.org/patch/12453/. This modification seems to fix an issue on a specific platform.
But I don't understand why to swap __ss_align and __ss_padding in struct sockaddr_storage.
The Qualcomm platform I'm now developing on has lots of typecast as follows.
struct sockaddr_storage prefix_addr
(struct sockaddr_in6 *)&(prefix_addr)->sin6_addr.s6_addr
On our Cortex A7 platform, struct alignment are as follows:
Before glibc2.23:
struct sockaddr_in6
{
sin6_family; //0th byte
sin6_port; //2nd byte
sin6_flowinfo; //4th byte
sin6_addr; //8th byte
};
struct sockaddr_storage
{
ss_family; //0th byte
__ss_align; //4th byte
__ss_padding; //8th byte
};
After glibc2.23:
struct sockaddr_storage
{
ss_family; //0th byte
__ss_padding; //2nd byte
__ss_align; //124th byte
};
glibc changed struct sockaddr_storage, but struct sockaddr_in6 is not changed, so this modification would cause many alignment issues on our platform, which lead getting IPV6 addresses errors.
Please refer to the reply from the Florian:
On 09/01/2017 12:07 PM, honan li wrote:
define SASTORAGE_DATA(addr) (addr).__ss_padding
typedef struct qcmap_cm_nl_prefix_info_s {
boolean prefix_info_valid;
unsigned char prefix_len;
unsigned int mtu;
struct sockaddr_storage prefix_addr;
struct ifa_cacheinfo cache_info;
} qcmap_cm_nl_prefix_info_t;
void QCMAP_Backhaul::GetIPV6PrefixInfo(char *devname,
qcmap_cm_nl_prefix_info_t
*ipv6_prefix_info)
{
struct sockaddr_in6 *sin6 = NULL;
...
sin6 = (struct sockaddr_in6 *)&ipv6_prefix_info->prefix_addr;
memcpy(SASTORAGE_DATA(ipv6_prefix_info->prefix_addr),
RTA_DATA(rta),
sizeof(sin6->sin6_addr));
...
}
Currently publicly available here:
https://github.com/Bigcountry907/HTC_a13_vzw_Kernel/blob/master/vendor/qcom/proprietary/data/mobileap_v2/server/src/QCMAP_ConnectionManager.cpp#L3658
I would expect applications do something like this instead:
struct sockaddr_in6 sin6; memset (&sin6, 0, sizeof (sin6));
sin6.sin6_family = AF_INET6; memcpy (&sin6.sin6_addr, RTA_DATA
(rta), sizeof (sin6.sin6_addr)); memcpy
(&ipv6_prefix_info->prefix_addr, &sin6, sizeof (sin6));
This avoids any aliasing issues and a dependency on the internals of
struct sockaddr_storage (which is only intended as a way to allocate a
generic struct sockaddr of sufficient size and alignment). It also
initializes the other components of the socket address (such as the
port number and flow label).
Thanks, Florian
Also refer to:
https://books.google.com.hk/books?id=ptSC4LpwGA0C&pg=PA72&lpg=PA72&dq=alignment+sufficient&source=bl&ots=Kt0BQhjiMt&sig=HTUbm2bzVNSoMxNX98EMzORFc30&hl=zh-CN&sa=X&ved=0ahUKEwiP78iMoovWAhVLipQKHYFdCxcQ6AEIQzAF#v=onepage&q=alignment%20sufficient&f=false
Conclusion is Qualcomm's usage of sockaddr_storage is incorrect.
I'm not sure this is the change in glibc that generates alignment warnings: this change has no effect on the source code you show.
On the contrary, I think Qualcomm is using clang, and beginning with clang 4.x, there is a new alignment warning that I've seen generating false positive warning about alignements, depending on the way you write your code: -Waddress-of-packed-member.
You should check if the clang version you are using has changed, since glibc changed. If this is the case, this could certainly explain your problem.
Using a temporary variable makes those warning disappear.
instead of making a call like:
my_function(((struct sockaddr_in6 *)&prefix_addr)->sin6_addr.s6_addr)
just write:
struct sockaddr_in6 p = *(struct sockaddr_in6 *) &prefix_addr;
my_function(p.sin6_addr.s6_addr);
This may avoid alignment warnings.
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.
Using a union like this is safe,
from C11 §6.5.2.3:
A postfix expression followed by the . operator and an identifier designates a member of
a structure or union object. The value is that of the named member,95) and is an lvalue if
the first expression is an lvalue. If the first expression has qualified type, the result has
the so-qualified version of the type of the designated member.
95) If the member used to read the contents of a union object is not the same as the member last used to
store a value in the object, the appropriate part of the object representation of the value is reinterpreted
as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type
punning’’). This might be a trap representation.
and
One special guarantee is made in order to simplify the use of unions: if a union contains
several structures that share a common initial sequence (see below), and if the union
object currently contains one of these structures, it is permitted to inspect the common
initial part of any of them anywhere that a declaration of the completed type of the union
is visible. Two structures share a common initial sequence if corresponding members
have compatible types (and, for bit-fields, the same widths) for a sequence of one or more
initial members
(highlighted what I think is most important)
With accessing the struct sockaddr member, you will read from the common initial part.
Note: This will not make it safe to pass pointers to the members around anywhere and expect the compiler knows they refer to the same stored object. So the literal version of your example code might still break because in your test() the union is not known.
Example:
#include <stdio.h>
struct foo
{
int fooid;
char x;
};
struct bar
{
int barid;
double y;
};
union foobar
{
struct foo a;
struct bar b;
};
int test(struct foo *a, struct bar *b)
{
a->fooid = 23;
b->barid = 42;
return a->fooid;
}
int test2(union foobar *a, union foobar *b)
{
a->a.fooid = 23;
b->b.barid = 42;
return a->a.fooid;
}
int main(void)
{
union foobar fb;
int result = test(&fb.a, &fb.b);
printf("%d\n", result);
result = test2(&fb, &fb);
printf("%d\n", result);
return 0;
}
Here, test() might break, but test2() will be correct.
Given the address_t union you propose
typedef union address
{
struct sockaddr sa;
struct sockaddr_in sa_in;
struct sockaddr_in6 sa_in6;
struct sockaddr_storage sa_stor;
}
address_t;
and a variable declared as address_t,
address_t addr;
you can safely initialize addr.sa.sa_family and then read addr.sa_in.sin_family (or any other pair of aliased _family fields). You can also safely use addr in a call to recvfrom, recvmsg, accept, or any other socket primitive that takes a struct sockaddr * out-parameter, e.g.
bytes_read = recvfrom(sockfd, buf, sizeof buf, &addr.sa, sizeof addr);
if (bytes_read < 0) goto recv_error;
switch (addr.sa.sa_family) {
case AF_INET:
printf("Datagram from %s:%d, %zu bytes\n",
inet_ntoa(addr.sa_in.sin_addr), addr.sa_in.sin_port,
(size_t) bytes_read);
break;
case AF_INET6:
// etc
}
And you can also go in the other direction,
memset(&addr, 0, sizeof addr);
addr.sa_in.sin_family = AF_INET;
addr.sa_in.sin_port = port;
inet_aton(address, &addr.sa_in.sin_addr);
connect(sockfd, &addr.sa, sizeof addr.sa_in);
It is also okay to allocate address_t buffers with malloc, or embed it in a larger structure.
What's not safe is to pass pointers to individual sub-structures of an address_t union to functions that you write. For instance, your test function ...
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!
}
... may not be called with (void *)a equal to (void *)b, even if this happens because the callsite passed &addr.sa and &addr.sa_in as the arguments. Some people used to argue that this should be allowed when a complete declaration of address_t was in scope when test was defined, but that's too much like "spukhafte Fernwirkung" for the compiler devs; the interpretation of the "common initial subsequence" rule (quoted in Felix's answer) adopted by the current generation of compilers is that it only applies when the union type is statically and locally involved in a particular access. You must write instead
sa_family_t test2(address_t *x)
{
x->sa.sa_family = AF_UNSPEC;
x->sa_in.sa_family = AF_INET;
return x->sa.sa_family;
}
You might be wondering why it's okay to pass &addr.sa to connect then. Very roughly, connect has its own internal address_t union, and it begins with something like
int connect(int sock, struct sockaddr *addr, socklen_t len)
{
address_t xaddr;
memcpy(xaddr, addr, len);
at which point it can safely inspect xaddr.sa.sa_family and then xaddr.sa_in.sin_addr or whatever.
Whether it would be okay for connect to just cast its addr argument to address_t *, when the caller might not have used such a union itself, is unclear to me; I can imagine arguments both ways from the text of the standard (which is ambiguous on certain key points having to do with the exact meanings of the words "object", "access", and "effective type"), and I don't know what compilers would actually do. In practice connect has to do a copy anyway, because it's a system call and almost all memory blocks passed across the user/kernel boundary have to be copied.
I am getting the following error through the coverity tool -
overrun-buffer-arg: Overrunning struct type in_addr of 4 bytes by passing it to a function which accesses it at byte offset 7 using argument "8UL".
sample code:
static u_long addr;
static struct sockaddr_in remote_server;
addr = inet_addr(remote_servername);
memcpy((char *) &remote_server.sin_addr, (char *)&addr, sizeof(addr));
In the last line, I am getting the above error.
Can someone through some light on, what's going wrong.
Please let me know, if you need any more information.
inet_addr() returns an in_addr_t, not an u_long.
struct sockaddr_in's sin_addr is a struct in_addr, which holds an in_addr_t s_addr.
This should do the trick:
static struct sockaddr_in remote_server;
remote_server.sin_addr.s_addr = inet_addr(remote_servername);
Standard warning: Do not cast a pointer to/from void *.
For the message: read it carefully, it very well states the problem. Just a hint: Use proper types. You are apparently accessing a struct beyond its size. Which size doe u_long have actually?
addr should be serialized properly to an uint8_t[], respecting endianess. As you take sizeof() from the second argument, apparently the first argument is shorter.
Why do you not just assign, but use memcpy()? Check both have the same type.
struct hostent *lh = gethostbyname(hostname);
int socketDescriptor = socket(AF_INET,SOCK_STREAM, 0);
sockaddr_in socketInfo;
memset(&socketInfo, 0, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_addr.s_addr = ((in_addr *)(lh->h_addr))->s_addr;
socketInfo.sin_port = htons(portNumber);
connect(socketDescriptor,&socketInfo,sizeof(socketInfo));
When trying to compile, I get the following error:
error: cannot convert ‘sockaddr_in*’ to ‘const sockaddr*’ for argument ‘2’ to ‘int connect(int, const sockaddr*, socklen_t)’
Things look "by the book", but I am missing something (obviously). What is it?
I think you are missing struct on sockaddr_in socketInfo. So it should be struct sockaddr_in socketInfo.
Also casting socketInfo to struct sockaddr * would be nice.
connect(socketDescriptor,&socketInfo,sizeof(socketInfo));
Should be
connect(socketDescriptor,(struct sockaddr *) &socketInfo,sizeof(socketInfo));
struct addrinfo *server;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));/*set hints*/
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
getaddrinfo(srvname,port,&hints,&server); /*get server ip fit args*/
sid = socket(server->ai_family, server->ai_socktype,server->ai_protocol)
connect(sid,server->ai_addr, server->ai_addrlen)
Those are some codesnipets that will work and that you can start from.
What happens here is that I set up one struct with all the intel and than combine it with some more info to get one nice all pointers fit structure too pass to connect.
hope that helps
The socket interfaces, in addition to being very old, are deliberately broken in this way. The sockaddr_* structs implicitly start with the same members of sockaddr so it's safe to cast them to the "base" type. struct sockaddr also has an sa_family member so you can also decide at runtime given a struct sockaddr* which "derived" (though not really) type to cast it to.
So, the smallest thing you can do to change this is cast the struct sockaddr_in* to struct sockaddr*. Normally this would be very offensive. But don't worry; in this instance everyone is doing it. I might even prefer to cast to void* because it's fewer characters and you'll get the implict conversion to struct sockaddr*.
However... A few other unrelated points:
gethostbyname can fail. In fact it happens pretty often, say when the user types in a bogus address. Your program will crash when that happens. Check to see if it returned NULL to avoid this.
Actually, gethostbyname has been superseded by getaddrinfo. Use that. It will get you protocol-independence so that you're not tied to IPv4. It also returns you a struct sockaddr* so you don't have to do the ugly cast.
If it was just the const it would work, but obviously sockaddr and sockaddr_in are different types.
I'm using Beej's Guide to Networking and came across an aliasing issue. He proposes a function to return either the IPv4 or IPv6 address of a particular struct:
1 void *get_in_addr( struct sockaddr *sa )
2 {
3 if (sa->sa_family == AF_INET)
4 return &(((struct sockaddr_in*)sa)->sin_addr);
5 else
6 return &(((struct sockaddr_in6*)sa)->sin6_addr);
7 }
This causes GCC to spit out a strict-aliasing error for sa on line 3. As I understand it, it is because I call this function like so:
struct sockaddr_storage their_addr;
...
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
connection_name,
sizeof connection_name);
I'm guessing the aliasing has to do with the fact that the their_addr variable is of type sockaddr_storage and another pointer of a differing type points to the same memory.
Is the best way to get around this sticking sockaddr_storage, sockaddr_in, and sockaddr_in6 into a union? It seems like this should be well worn territory in networking, I just can't find any good examples with best practices.
Also, if anyone can explain exactly where the aliasing issue takes place, I'd much appreciate it.
I tend to do this to get GCC do the right thing with type-punning, which is explicitly allowed 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;
I tend to do this to get GCC do the right thing with type-punning, which is explicitly allowed with unions
I am pretty sure this (mis)use of union will not work (or only by accident) with GCC:
short type_pun2 (int i, int *pi, short *ps) {
*pi = i;
return *ps;
}
union U {
int i;
short s;
};
short type_pun (int i) {
U u;
return type_pun2 (i, &u.i, &u.s);
}
The correct way to do that is with memcpy, not union.
I recently had a similar alias warning on HPUX system when trying to write code to get the MAC address of the machine
The &(((struct sockaddr_in *)addr)->sin_addr) complains about strict-aliasing rules
This is the code in some context
char ip[INET6_ADDRSTRLEN] = {0};
strucut sockaddr *addr
...
get addr from ioctl(socket,SOCGIFCONF...) call
...
inet_ntop(AF_INET, &(((struct sockaddr_in *)addr)->sin_addr),ip,sizeof ip);
I overcame the aliasing warning by doing the following
struct sockaddr_in sin;
memcpy(&sin,addr,sizeof(struct sockaddr));
inet_ntop(AF_INET, &sin.sin_addr,ip,sizeof ip);
And whilst this is potentially dangerous I added the following lines before it
static_assert(sizeof(sockaddr)==sizeof(sockaddr_in));
I'm not sure if that is something would be considered bad practice, but it worked and was cross platform to other *Nix flavors and compilers
The issue has nothing to do with the call to the function. Rather, it's with ((struct sockaddr_in*)sa)->sin_addr. The problem is that sa is a pointer of one type, but you're casting it to a pointer of a different type and then dereferencing it. This breaks a rule called "strict aliasing", which says that variables of different types can never alias. In your case, aliasing to a different type is exactly what you want to do.
The simple solution is to turn off this optimization, which allows aliasing in this manner. On GCC, the flag is -fno-strict-aliasing.
The better solution is to use a union, as mentioned by Nikolai.
void *get_in_addr(struct sockaddr *sa)
{
union {
struct sockaddr *sa;
struct sockaddr_in *sa_in;
struct sockaddr_in6 *sa_in6;
} u;
u.sa = sa;
if (sa->sa_family == AF_INET)
return &(u.sa_in->sin_addr);
else
return &(u.sa_in6->sin6_addr);
}
That said, I can't actually get GCC to give me a warning when using your original code, so I'm not sure if this buys you anything.