前段时间的一个小插曲,刚刚提交了一段代码,结果一个拥有十年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函数更加需要考虑各种情况。
void getBlocks(int (&blockList)[10] ); // 2. 传数组引用,数组固定为10,函数中只能访问0-9。
template<typename Type, int SIZE> void getBlocks(Type (&arr)[SIZE]);// 3. 模版函数,任意长度数组引用。函数中根据SIZE控制数组访问行为。
#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函数则每次访问数组前都进行越界判断,大大减小多线程导致数组越界后的危害。