概述
一、引言
在提供给客户的bin档突然在最新版就不能用了,而客户提供的出错log 跟bin 档本身的功能却一点也没有关系,最后只能一点点回退修改的代码来排查,最终定位的问题确是数组越界导致的异常。
二、问题追溯
在当前的案例中,我们会提供一个bin档给客户,客户使用我们提供的API 接口通过UART 加载外置的DSP。同时为了追溯bin档的版本号,定义了一个接口来获得加载成功之后的版本号。如下面的示例代码:
static int dsp_get_algorithm_version(void)
{
#define MAX_LABLE_SIZE 20
int rc = 0;
uint32 cmd,rsp;
char algo_version[MAX_LABLE_SIZE]={0};
uint8 index = 0;
/*
*
iteratively to retrieve successive Build string characters, which
*
terminates when a 0 binary value is retrieved.
*/
while((char)rsp){
cmd = DSP_GET_NEXT_BUILDLABEL;
rc = dsp_uart_cmd(cmd, &rsp);
if (rc){
LOD_D(("%s(): Set chip cmd fail %dn",
__func__, rc));
goto read_algo_version_error;
}
algo_version[index++] = (char)rsp;
}
LOG_D(("algorithm_version:%sn",algo_version));
read_algo_version_error:
return rc;
}
该函数预定义了一个20bytes 的数组用来存放通过uart接口获得的版本号,每次读取获得一个字节。在最新的dsp 版本中,版本号改成了超过20字节的字符串,连续的读取导致字符数组越界了,程序死在了莫名奇妙的地方,导致花了很长的时间才找到了问题。
复盘产生这种问题的原因,一是版本号没有按照事先约定的最大长度来定义;二是上层没有对可能产生的这种错误进行检查和保护,从而事后花很长的时间进行调试,这也体现了《代码大全》中所提到的防御性编程方法。
回到这个例子,对代码做如下的变动,检测读取的长度是否超过最大长度,如果超过最大长度,做截断处理:
static int dsp_get_algorithm_version(void)
{
#define MAX_LABLE_SIZE 20
int rc = 0;
uint32 cmd,rsp;
char algo_version[MAX_LABLE_SIZE]={0};
uint8 index = 0;
/*
*
iteratively to retrieve successive Build string characters, which
*
terminates when a 0 binary value is retrieved.
*/
while((char)rsp && (index < MAX_LABLE_SIZE)){
cmd = DSP_GET_NEXT_BUILDLABEL;
rc = dsp_uart_cmd(cmd, &rsp);
if (rc){
LOD_D(("%s(): Set chip cmd fail %dn",
__func__, rc));
goto read_algo_version_error;
}
algo_version[index++] = (char)rsp;
}
if(index == MAX_LABLE_SIZE && algo_version[index - 1] != '