我们目前正在开发一种能够读取CAN消息并评估所包含数据的小工具。当char数组bind()
太短,太长或不存在时,empty
命令不会返回0(对于成功绑定)。这个错误出现在下面的缩短程序中。
#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");
}
}
行为随着char数组empty
的长度而变化。
例如,[5]
有效,而[24]
则无效。
我们用GCC 5.4.0和7.2.0对它进行了测试,两者都显示了这种行为。
根据GCC 5.3.0,empty
的存在和长度不会影响我们的bind()
。
作为参考,我们使用了
gcc main.c
./a.out
为什么我们需要一个未使用的带有GCC 5.4.0和7.2.0的char数组来成功绑定?
答案 0 :(得分:4)
由于使用了未初始化的变量,导致各种未定义的行为。
您永远不会初始化ifr
,然后使用ifr.ifr_ifindex
。
您永远不会初始化addr.tp
,然后将addr
作为sockaddr
参数传递给bind()
。
它总是成功比失败取决于empty
数组的大小这一事实更令人惊讶。您希望套接字绑定到哪个地址?
答案 1 :(得分:3)
我们按照kernel.org上的文档进行了操作。
In&#34; 4。如何使用SocketCAN&#34; (约60行)这个例子给出了:
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));
(..)
虽然它声明没有执行任何错误检查,addr
和ifr
都没有完全初始化(就像你在这里提到的所有人一样)。因此,给定的示例遇到与我们的程序相同的问题。
使用memset
(例如@zwol)初始化它们以确保在使用它们之前将所有值设置为0可以完全修复此意外行为。
谢谢大家。