概述
本文介绍了Bug系列的第2个Bug,讲的是解析报文时,模拟了一个无效的数据长度,触发了C语言函数的隐式规则转换,导致任务进入了超长的循环处理,进而导致运行时错误(Running Time Error)。就如何避免这个问题提出了解决方案,并进行了经验总结。
阅读本文需要了解C语言隐式规则转换的理论基础。
背景
项目需要对基于串口的通信协议进行解析,根据包头确定后续接收数据的长度。后期测试过程中,发现模拟无效数据长度,会导致整个ECU触发运行时错误(Running Time Error ),进而导致程序挂掉。
主体代码
#include <stdio.h>
#include <stdint.h>
#define FRAME_HEAD_SIZE (4U)
uint32_t g_u32_Counter = 0;
uint32_t g_u32_dataLen = 0;
int main()
{
uint32_t index = 0;
//dispatch data length from the protocol, simulate invalid data length 2.(shall be bigger than 4 in normal)
g_u32_dataLen = 2;
for(index = 0; index < g_u32_dataLen - FRAME_HEAD_SIZE; index++)
{
g_u32_Counter++;
}
printf("expected received data counter is %u\n", g_u32_Counter);
}
运行环境
- Software: AutoSar OS, CP4.2.2
- Hardware: S32K146
主要功能
这段代码模拟数据的解析过程,模拟了数据长度为2的报文,但是由于包头固定大小已经是4,会导致index < -2 这种不可思议的判断条件。
那么这种情况下,g_u32_Counter的值会是多少呢?
相信不少人会觉得条件不满足,不会进入循环,值为0。
但是,实际情况是,g_u32_Counter = 4294967294 (0xFF FF FF FE)。
为什么呢?
因为这里发生了C语言的隐式规则转换。粗浅的解释是,在进行同等长度的无符号和有符号的数据计算时,会将有符号数据先转换为无符号数据,然后进行计算。
更深层次的原因是,-2是个负数,在计算机里面是以补码的形式存在,即0xFF FF FF FE, 因而,整个循环次数非常大,触发了Autosar的运行时错误。
该情况很容发生在非法的网络攻击上,需要设计鲁邦的程序,至少坚持到程序被攻克前,保证程序的正常运行。(当然你想通过这种方式来保护程序不受侵害也算是脑洞大开)。
如何避免这个问题
其实只需要做好关键的数据长度检查,无效数据长度进行过滤,并且在设计程序时对关键等价类或者边界充分考虑。
总结
该问题给我们也有一起启发,很多时候,开发更多考虑的是正向,保证基本的功能,而好的测试更多像精密的勘测仪器,帮助我们发现软件中的缺陷,保证整体软件功能和非功能有效性。
测试开发独立
流程上,尽量保证开发和测试独立性,避免既是运动员又是裁判。
测试驱动开发
作为开发人员,应该更多地借鉴测试的一些方法进行编程,比如等价类,边界值等等,保证整体软件质量。