Reputation: 41
We're currently developing a small tool that reads CAN-messages and evaluates the data contained. The bind()
command doesn't return 0 (for a successfull bind) when the char array empty
is too short, too long or not present. This bug is present in the shortened program below.
#include <sys/socket.h> // socket, bind, PF_CAN, SOCK_RAW
#include <linux/if.h> // ifreq
#include <linux/can.h> // sockaddr_can, CAN_RAW
#include <stdio.h> // printf
int main()
{
struct sockaddr_can addr;
struct ifreq ifr;
int socketFd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
addr.can_ifindex = ifr.ifr_ifindex;
char empty[5]; // change length or comment out to provoke the error
if(bind(socketFd, (struct sockaddr *) &addr, sizeof(addr)) != 0)
{
printf("Unable to bind the CAN-socket.\n");
}
}
The behaviour changes with the length of our char array empty
.
For example [5]
works, while [24]
doesn't.
We tested this with GCC 5.4.0 and 7.2.0 which both showed this behaviour.
Under GCC 5.3.0 the presence and lentgh of empty
do not influence our bind()
.
For reference we used
gcc main.c
./a.out
Why do we need an unused char array with GCC 5.4.0 and 7.2.0 for a successfull bind?
Upvotes: 0
Views: 105
Reputation: 41
We followed the documentation found at kernel.org.
In "4. How to use SocketCAN" (approx. line 60) this example is given:
int s;
struct sockaddr_can addr;
struct ifreq ifr;
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));
(..)
While it states that no error checking has been implemented neither addr
nor ifr
have been fully initialised (like all of you mentioned here). Therefore the given example encounters the same problem as our program.
Initialising them with memset
like @zwol mentioned to ensure all values are set to 0 before working with them fixes this unexpected behaviour completely.
Thanks everyone.
Upvotes: 3
Reputation: 780889
You're causing all sorts of undefined behavior due to use of uninitialized variables.
You never initialize ifr
, then you use ifr.ifr_ifindex
.
You never initialize addr.tp
, then you pass addr
as the sockaddr
parameter to bind()
.
That it ever succeeds at all is more surprising than the fact that the failure depends on the size of the empty
array. What address are you expecting the socket to be bound to?
Upvotes: 4