如何防止缓冲区溢出/数组溢出?

4
我最近在为自定义串行通信协议编写代码。我使用接收数据的一部分(8/16位)来表示帧大小。根据这个数据,我期望有一定数量的数据跟随。我使用Crc来接受或拒绝一个帧。但是,在处理一个帧之前,我无法将帧长度数据包含在Crc中,因为在接收端,我应该知道要期望多少数据。
我遇到的问题是,偶尔这个帧长度数据会损坏,并欺骗接收器接收那么多字节,而接收数组大小远小于那个数值。这会破坏许多关键系统变量,这些变量存在于连续的内存位置中。
如何防止缓冲区溢出?我的想法是: 1)如果超过某个值,则拒绝帧长度数据。 2)使用限制最大数量的数据类型。例如,使用short将数组索引范围限制在256个内存位置内,并创建一个具有280个字节的缓冲区。 3)在单独的位置分配内存,这样就不会影响关键系统变量。
为了防止陷入接收循环中,我使用超时来预防。但是我忽略了这个问题的方面。由于这段代码是大型系统代码的一部分,而我不是专家,所以花了很长时间来确认和重现这个问题。
通常如何安全地处理这种问题? 此外:在使用数组时,有哪些一般考虑因素或标准实践可以防止溢出?

2
发送缓冲区长度两次(第二次可能是反转的)。如果匹配,就没问题。 - Weather Vane
1
您可以通过选择包括奇偶校验位的串行协议来改善错误检测。 - John Bollinger
3
简单的解决方案就是这样。另一个解决方案是发送一个固定大小的头部,该头部本身具有CRC或某种前向纠错。 - user3386109
3
即使客户端接收到一个损坏的帧长度,也没有理由可以愚弄客户端进入缓冲区溢出。客户端知道它的缓冲区大小,并且完全控制存储字节的数量和位置。 - John Bollinger
2
无论如何,没有100%可靠的错误检测机制。这完全取决于你想要投入多少数据和计算量来进行错误检测,以及你希望数据被损坏的概率有多小,以至于无法被检测到。 - John Bollinger
显示剩余10条评论
2个回答

1
有很多方法可以用来减少这个问题,但是一般情况下没有一种适合所有情况的解决方案。你必须做出决策,并了解如果出现问题会发生什么,并使系统能够处理它。
你必须弄清楚什么最适合你的系统。例如,如果您从未期望消息大于256,则将缓冲区的大小声明为0xFF,将缓冲区的索引声明为uint8_t,您永远无法超过插入一个字节时索引不会达到256并溢出回到0的限制。当然,这样做的缺点是,如果确实发生这种情况,则会覆盖一些接收到的数据,但crc检查应在大多数情况下显示错误。
另一件事情是将数据长度与缓冲区最大值进行比较,如果超过缓冲区,则不存储消息。因此,您将直接拒绝任何数据长度太大且已接收到的消息,但不存储跨越的数据。显然,如果数据长度经常损坏,则会遇到许多问题。
说实话,最好的方法是重新思考你的自定义串行通信协议。听起来它似乎无法很好地处理你遇到的错误。你可以在消息的开头和结尾添加同步字节,以确保你实际上接收到了好的数据,并对整个消息进行CRC校验,而且定义最大数据包大小,这些数据包将通过线路传输,并指示需要接收多少个数据包。如果通信协议不是很好,那么你必须从底层重新考虑它。

我将尝试使用unit8。我已经在帧的开头使用同步字节。只有在检测到同步字节后,我才获取此帧大小数据。似乎数据损坏发生在帧中的随机字节,而其他字节似乎正常。 - seetharaman

1
首先,检查是否存在帧错误和奇偶校验错误。
其次,检查数据大小的幅度。如果太大或太小,则拒绝整个数据块。

我正在使用头文件来检测帧的起始位置和进行位定位。至于奇偶校验,我没有使用UART,因此在软件中进行计算将会增加开销。检查帧的大小并拒绝可能是可行的。 - seetharaman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接