谈谈数组的潜在越界行为

102 篇文章 0 订阅
33 篇文章 0 订阅

1. 字符串函数调用

前段时间的一个小插曲,刚刚提交了一段代码,结果一个拥有十年C/C++开发经验的牛人立刻给我发了一段消息:

char cfgPath[MAX_FILE_NAME];  
char m_szBaseDir[MAX_FILE_NAME];

SysStrncpy( cfgPath, m_szBaseDir, SysStrlen(m_szBaseDir) ); 这样估计有问题
SysStrncpy( cfgPath, m_szBaseDir, MAX_FILE_NAME); 一般这样用,也有问题,但问题小些
真心佩服这个牛人,火眼金睛发现第一种写法的问题:防止m_szBaseDir字符串没有结束符导致越界,

字符串拷贝需要考虑两个字符数组长度,如果一样,第三个参数用他们的长度最安全。二者不等需要确保两个数组均不能越界!当然自己写strncpy函数更加需要考虑各种情况。

2. 接口设计减少越界行为

void getBlocks(int* blockList, int listNum); // 1. 直接传数组,数组作为函数参数传入时,因为C++函数参数中,数组会decay为指针,函数内部无法获得数组大小,需要另外传一个数组大小参数。

void getBlocks(int (&blockList)[10] ); // 2. 传数组引用,数组固定为10,函数中只能访问0-9。
template<typename Type, int SIZE> void getBlocks(Type (&arr)[SIZE]);// 3. 模版函数,任意长度数组引用。函数中根据SIZE控制数组访问行为。

3. 恶果

最近我们的APP,CRASH概率很高,根据logcat中绿色信息总是指向native层两个函数。crash行为很随机,加之android NDK调试工具十分不成熟,logcat中的日志结合so包的汇编只能定位到函数。要找到哪一句crash基本不太可能,能够定位到代码行也不能查看crash现场各变量数据。
昨天测试人员发现了按照某种规律操作,能大大提高crash复现概率,看crash行的汇编str指令 怀疑是 数组越界。用最新的ndk-r8c版本搭建一个调试框架,不断反复操作APP,crash之后也不能保留现场!只能看到 segment_fault再次怀疑数组越界!通过不断增加log最终证实自己判断,导致数组越界的代码模型如下:
#define MAX_LEN 100
int	gBuffer[MAX_LEN];
int gBufferCursor = 0;

void foo_v1() 
{
	gBufferCursor = 0;
	for (int idx=beg; idx <= end; idx++) 
	{
		// ...
		
		gBuffer[ gBufferCursor ] = idx;
		gBufferCursor++;
		
		gBuffer[ gBufferCursor ] = idx;
		gBufferCursor++;
		
		if (gBufferCursor==MAX_LEN) 
		{
			print(gBuffer);
			gBufferCursor = 0;
		}
		
		// ...
	}
}
正常情况看foo_v1,循环中每次往数组中加两个数,数组长度是100偶数,无论如何gBufferCursor==MAX_LEN情况都会出现。但实际打log着实惊讶,crash的时候gBufferCursor居然飙到了1000+。 代码中使用等于判断过于严格而且一旦游标gBufferCusor超过MAX_LEN则没有一点补救措施,只要for循环继续则会不断访问gBuffer数组之外的内容,而且gBuffer还是全局数组(参见 全局变量的陷阱)。将 等于改成 大于等于,在gBuffer越界后还能及时重置游标,但gBuffer数组还是有越界可能。
更加保险的做法:
void foo_v2() 
{
	gBufferCursor = 0;
	for (int idx=beg; idx <= end; idx++) 
	{
		if ( gBufferCursor>=MAX_LEN-2 ) 		// 防止下面code越界行为
		{
			print(gBuffer);
			gBufferCursor = 0;
		}
		gBuffer[ gBufferCursor ] = idx;
		gBufferCursor++;
		
		gBuffer[ gBufferCursor ] = idx;
		gBufferCursor++;		
	}
}
整整一天终于FIX了native层这个神奇的BUG。 问题根因是:多线程访问全局变量资源,导致数组游标行为异常,造成数组越界访问,进而CRASH。foo_v1如果数组越界一定会导致APP crash;foo_v2函数则每次访问数组前都进行越界判断,大大减小多线程导致数组越界后的危害。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值