Keil调试笔记:数组越界

概要:一个例子,两个思路,一些思考。

问题现象

struct bmm150_dev {
	/*! Chip Id */
	uint8_t chip_id;
	/*! Device Id */
	uint8_t dev_id;
	/*! SPI/I2C Interface */
	enum bmm150_intf intf;
	/*! Bus read function pointer */
	bmm150_com_fptr_t read;
	…//此处为省略
};

//定义一个结构体变量
struct bmm150_dev MagDev ;
//检查不BUG的地方
static int8_t null_ptr_check(const struct bmm150_dev *dev)
{
	int8_t rslt;

	if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL) ) {
		/* Device structure pointer is not valid */
		rslt = BMM150_E_NULL_PTR;
	} else {
		/* Device structure is fine */
		rslt = BMM150_OK;
	}

	return rslt;
}

注:以上代码是由博世的BMM150的开源驱动。程序是在Stm32上运行的。

在传感器通过MagDev句柄读取传感器数据,在调用API函数周期性读取传感器函数时,通常都会判断句柄是否有效。而出现的现象是程序运行一会儿后,发现“(dev->read == NULL)”为真了,而MagDev.read是在程序初始化时就不再改变的值。也就是说该值被意外篡改了。

查找问题引发源的方式1

程序还没调用操作系统,但此时已经有开启了几个中断了。

1、首先我先把所有中断都屏蔽了,只运行主函数,现象不再现。

2、每次只打开一个中断,在调试模式下依次排查。问题复现并找到原因。

我定义了如下变量

static double AGdataSum[6] = {0};

但由于需求改变,实际上使用了7个double值,于是由于数组越界,意外改变了下一个静态/全局变量的值。

查找问题引发源的方式2

==============================================================================

Image Symbol Table

    Local Symbols

    Symbol Name                              Value     Ov Type        Size  Object(Section)

    adcBuf                                   0x240041a2   Data          14  cfileObject1.o(.bss)

    AGdataSum                                0x240041b0   Data          56 cfileObject1.o(.bss)

    .bss                                     0x240041e8   Section       72  magnetrun.o(.bss)

    .bss                                     0x24004230   Section      192  cfileObject2.o(.bss)

    .bss                                     0x240042f0   Section     1044  cfileObject3.o(.bss)

    Global Symbols

    Symbol Name                              Value     Ov Type        Size  Object(Section)

    sensorData_value                         0x24004068   Data         112  cfileObject4.o(.bss)

    MagDev                                   0x240041e8   Data          72  magnetrun.o(.bss)

    next_value                           0x24004230   Data          64  cfileObject2.o(.bss)

==============================================================================

注:此表是在BUG还没修改前的表,表中部分内容已经匿名处理。“”为省略部分。

 

其实我一开始就怀疑是数组越界,于是到map文件中查找。但以为编译器将全局变量一次存在RAM中,找到变量MagDev后面的 变量next_value 的相关程序,并未发现有什么问题。后来才知道,编译器分配全局变量和静态变量的内存时,编译器内存不是先分配静态变量内存后分配全局变量的方式进行的,而是按文件搜索顺序分配内存。

变量 AGdataSum的地址加上其内存大小后就是变量MagDev 的首地址了。显然如果变量 AGdataSum操作第7位时正好改变了变量MagDev的值。

0x240041b0+56=0x240041e8

 

MAP文件的说明

1、0x2400xxxx表明存储空间在RAM;若为0x0800xxxx,则表明存储空间为Flash。

2、静态变量区的符号名为“.bss”的部分可能会在全局变量区写出具体变量名。

 

思考:

1、局部变量使用的是栈,若出现错误,一般会使局部逻辑出错,也一般不会导致夸逻辑区域的错处。

2、计算资源不紧张的话,函数尽量每次使用函数指针时都判断一下指针是否为空,当然能让本文例子那样判断出BUG来也是要有一定运气的。

3、谨慎使用数组,谨慎使用指针,多写些检验程序,提高程序鲁棒性。

 

Keil调试笔记:数组越界Keil调试笔记:数组越界 NoDistanceY 发布了18 篇原创文章 · 获赞 5 · 访问量 6077 私信 关注
上一篇:C/C++程序内存分配


下一篇:iOS进阶收藏