简体   繁体   中英

Why do we need an unused char array for a successfull bind?

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?

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM