有些语言本身就会做数组访问越界检查,比如java,访问越界时会抛出java.lang.ArrayIndexOutOfBound.
C语言非常重视运行时的效率,所以没有进行数组越界检查,而C++继承了C的效率要求,也不做数组越界检查。
这样就会造成对未知内存的修改,带来很多意想不到的问题,造成重大影响,这类问题往往debug的时候也比较难以发现。
例
int main(int argc, char* argv[]){
int i = 0;
int array[3] = {0};
for(; i<=3; i++){
array[i] = 0;
printf("hello world\n");
}
return 0;
}
在部分编译器下,这个代码执行后是会陷入死循环的。
原因在于数组越界之后,修改的array[3]其实修改的内存是i所在,i被改成0,循环从头开始,如此往复。
分析
原来觉得根据栈帧结构,应该是地址从高到低放置变量,然后访问到了最先定义的在高地址的变量i,但是换了一下 int i = 0;的位置,还是死循环。
后来了解到,不同编译器是不同的,同时这也跟地址对齐方式有关,把array[3]改成array[4]之后,再修改循环条件<=4,也不会再发生死循环了。
解决方式
1
最简单,写的时候注意不要出错。或者,手动加一段代码,检查是否越界,不过这样确实会增加开销,影响效率。
2
gcc编译的时候是有 堆栈保护的选项的,会进行一些保护操作,比如强制将数组放在函数栈的高地址,而将其他变量放在低地址。
增加 -fstack-protector-all 就能为所有函数插入保护代码。
当然,这也有一些局限性,最好还是写代码的时候就注意保护。
具体可以查看 https://www.ibm.com/developerworks/cn/linux/l-cn-gccstack/