I compile a C program in Solaris and get this warning.
line 68: warning: improper pointer/integer combination: op "="
My code contains
struct cmsghdr *cmsg;
Line 68 is
cmsg = CMSG_FIRSTHDR(&msg);
The structure cmsghdr and CMSG_FIRSTHDR is defined in socket.h as
#define CMSG_FIRSTHDR(m)
--
--
struct cmsghdr {
socklen_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
I have included socket.h in my code. But still I get this error.
It is possible that the CMSG_FIRSTHDR macro doesn't do proper typecasting, so you have to do it yourself:
cmsg = (struct msghdr *) (CMSG_FIRSTHDR(&msg));
It might also be that there is some improper casting inside the macro itself, in which case there is nothing you can do, as it's in a system header.
please check what type SOL_SOCKET is. It needs to be int.
Change the type of the filed "cmsg_level" in your struct, if it dosen't match.
I guess SOL_SOCKET is a pointer, maybe int*
Related
As part of a function that receives a struct ifreq *ifr argument, if I declare struct sockaddr_in name;, the program compiles, but if I name the variable struct sockaddr_in ifr_addr;, it fails with the following error:
code.c:244:24: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘.’ token
struct sockaddr_in ifr_addr;
^
code.c:244:24: error: expected expression before ‘.’ token
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
The ifreq struct is declared as below. I know that the struct has a field with the same name than the problematic variable. How is that a problem in C?
struct ifreq {
char ifr_name[IFNAMSIZ]; /* Interface name */
union {
struct sockaddr ifr_addr;
struct sockaddr ifr_dstaddr;
struct sockaddr ifr_broadaddr;
struct sockaddr ifr_netmask;
struct sockaddr ifr_hwaddr;
short ifr_flags;
int ifr_ifindex;
int ifr_metric;
int ifr_mtu;
struct ifmap ifr_map;
char ifr_slave[IFNAMSIZ];
char ifr_newname[IFNAMSIZ];
char *ifr_data;
};
};
http://man7.org/linux/man-pages/man7/netdevice.7.html
When you get an error like that, it almost invariably means that a header, in this case probably one of the system headers, has defined a macro with the same name as you chose for your variable, but with an expansion that is not valid as an identifier.
You wouldn't see a problem if the header defines:
#define ifr_addr pwr_address
You do see a problem if, as you note in a comment, the expansion (in include/uapi/linux/if.h, near line 258) is:
#define ifr_addr ifr_ifru.ifru_addr
The macro is meant to make it easier to access elements of a union without having to specify the union member name each time. At times like this, you find yourself asking — was it worth it? (I see this in the code base I work on daily — a lot. It's hard, sometimes, to work out what the code is accessing.)
Although it would be possible to use:
#undef ifr_addr
before defining your own variable with that name, doing so is treading on thin ice. It's best to accept that the name is preempted and use something else, annoying though it is. A possibility is to use ifr_srcaddr, to match/contrast ifr_dstaddr.
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.
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.
I am getting some compilation errors I can't figure out, and although I'm sure they're quite stupid I can't find an answer that helps me much through other channels.
Problem 1: (These are a part of a TCP protocol)
error: ‘TH_SYN’ undeclared (first use in this function)
error: ‘TH_ACK’ undeclared (first use in this function)
tcp.tcph_flags = TH_SYN;
tcp.tcph_flags = TH_ACK;
Problem 2:
error: conversion to non-scalar type requested
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader ip;
struct tcpheader tcp;
ip = (struct ipheader) buffer; /* ERROR POINTS HERE */
tcp = (struct tcpheader) buffer + ip.iph_ihl *4; /* AND HERE */
Problem 3:
warning: assignment makes integer from pointer without a cast
case 'i': dip = inet_addr(optarg);
dstip = (optarg); /* ERROR POINTS TO THIS LINE */
break;
Now I hope I've copied enough relevant information on the errors for you to be able to help, but if I've left something out let me know. For problem 1, I believe I am missing a header file of some sort but I don't know which. Problem 2 and 3 are pointer issues, but I'm not sure why they aren't correct. Thanks in advance :)
For the first problem, include the header defining TH_SYN and TH_ACK. On my system it's netinet/tcp.h
For the second problem, turn ipheader and tcpheader into pointers
For the third problem I think you need a strtoul but I'm unsure
For problem 1, you need
#include <netinet/tcp.h>
For problem 2, struct ipheader should be struct ipheader * in both your declaration and cast, as well as struct tcpheader should be struct tcpheader *
For problem 3, optarg is a pointer, and needs to be dereferenced, so refer to it as *optarg