“段错误”是对内存非法调用的一个总称,因为从汇编的层面上来看,分配给可执行程序的内存都是分段使用的,有的段存储可执行代码,有的段存储堆,有的段存放静态数据等;
待解决,经排查初步认定是内存的过界访问(结构体数组的访问溢出)
背景:我在用一个UWB测距模块,在Nooploop空循环官方ROS驱动包中,发布标签节点的同时,在订阅方的回调函数中使用一个名为LinktrackAoaNodeframe0.msg的消息文件,内容如下:
查阅ROS Wiki相关资料,LinktrackAoaNode0[] nodes是msg文件结构体数组的一种定义方式,而在LinktrackAoaNode0这个msg文件中,可以看到nodes这个结构体数组中的成员,内容如下:
现在我仅仅想取LinktrackAoaNode0这个msg文件中的dis(float32)与angle(float32)两个成员,即距离与角度。然后就有以下问题:
我以两种方式打印数据,在程序在跑一段时间后会强行中止(不超过10秒),都会出现段错误(核心已转储),上网查阅很可能是“数组、向量等类似的类型是否产生了越界访问”
在去掉含数组的访问操作后,如下图,会发现程序会一直执行,不会报错。
有人可能会疑问nodes[]里的下标为什么是0?
msg->nodes[0].dis
我们可以简单看一下,发布方其中的一段内容:
void Init::InitAoaNodeFrame0(NProtocolExtracter *protocol_extraction)
{
auto protocol = new NLTAoa_ProtocolNodeFrame0;
protocol_extraction->AddProtocol(protocol);
protocol->SetHandleDataCallback([=] {
if (!publishers_[protocol])
{
auto topic = "nlink_linktrack_aoa_nodeframe0";
publishers_[protocol] =
nh_.advertise<nlink_parser::LinktrackAoaNodeframe0>(topic, 200);
TopicAdvertisedTip(topic);
}
const auto &data = g_nltaoa_nodeframe0.result;
auto &msg_data = g_msg_aoa_nodeframe0;
auto &msg_nodes = msg_data.nodes;
msg_data.role = data.role;
msg_data.id = data.id;
msg_data.local_time = data.local_time;
msg_data.system_time = data.system_time;
msg_data.voltage = data.voltage;
msg_nodes.resize(data.valid_node_count);
for (size_t i = 0; i < data.valid_node_count; ++i)
{
auto &msg_node = msg_nodes[i];
auto node = data.nodes[i];
msg_node.id = node->id;
msg_node.role = node->role;
msg_node.dis = node->dis;
msg_node.angle = node->angle;
msg_node.fp_rssi = node->fp_rssi;
msg_node.rx_rssi = node->rx_rssi;
}
publishers_.at(protocol).publish(msg_data);
});
}
我们只需要关注for (size_t i = 0; i < data.valid_node_count; ++i)中的valid_node_count,它代表基站的个数,而我只有一个标签和一个基站,即valid_node_count=1(valid_node_count如果为0,代表当前这一帧数据里面没有标签到基站的数据,可能是基站没有上电,也可能是丢包)
因为数组的第一个元素的下标为0,那么msg->nodes[0].dis代表第一个基站返回到标签的距离信息(因为我只有一个基站下标也只能为零,其它下标是不会返回数据的,而且理论上nodes.size的大小也应该等于1,我们可以验证一下)
可以看到距离和角度为无效信息。
查阅该AOA模块的用户手册中的协议(说明一下,当标签与基站上电后,协议会自行解析,我们要关注的是怎么使用解析后的数据信息)
其中valid_node_quantity变量代表这一帧数据里有几个block(变长协议),每个block里包含一个基站到标签的距离角度等数据。下图是block0一帧数据的所有信息。
这就是选nodes[0]的原因,回到一开始的问题,为什么出现“段错误 (核心已转储)”的意外中止,在去掉含数组的访问操作后,程序会一直执行,不会报错。我怀疑是结构体数组数据的访问溢出,那么这就是一个C++的语法问题了。
请问各位码友,那么我也该如何在回调函数中访问结构体数组才不会溢出呢? 还是说是其他问题?