严重.. 我是80年代的老黑客,有一些业余时间 在我的手上以为我'C'是什么大惊小怪的
(我的背景是Forth,它将事情做回到前面 所以我学到很多关于强迫许多错误的事情)
在这种情况下,我设置了一个小阵列,我 以为大小为3个元素(0,1,2)
如果我运行编译,我会想到 我有一个越界错误,但没有 - 它编译好并且运行得很好
这一点并不是很着急,但确实如此 对于那个小秃头的地方来说并不好,所有这些都在刮擦。
int main()
{
char members[3][16]; // 3 elements, each 15 char long plus null
printf("\n enter something.. ");
scanf( "%s", members[4]);
printf("\n and something else.. ");
scanf( "%s", members[5]);
printf(" %s ", members[4]);
printf(" %s\n", members[5]);
return 0;
}
答案 0 :(得分:5)
访问数组越界会调用未定义的行为。这意味着任何事情都可能发生,包括没有任何明显错误的运行。
答案 1 :(得分:3)
C不进行任何边界检查。 (Forth也没有,所以我不确定期望来自哪里。)
溢出数组是未定义的行为:允许(但不是必需)崩溃。在这种情况下,字节恰好与放置局部变量的堆栈帧位于同一虚拟内存页中。如果框架朝向页面的末尾,则CPU将识别出错误的地址并抱怨溢出。
如果你去了几千字节或几兆字节,你可能会看到像你期望的那样。
答案 2 :(得分:0)
通常,内存以4 kB页面分配。因此,在最后一个变量之后会有一些额外的空间,并且您的缓冲区溢出未被检测到。但是,如果您的members
数组后面有另一个变量并且您写入members[4]
,则另一个变量会被破坏。
valgrind和dmalloc等工具通常用于检测缓冲区溢出。他们的工作是在你的变量周围分配特殊的保护区域,并检查没有人在那里写过。
答案 3 :(得分:0)
您错过了堆栈上的主要返回地址,可能会覆盖主要调用方的一些非关键数据,因此您的程序不会崩溃。此外,在某些平台上(例如powerpc),堆栈不用于函数调用,返回地址存储在特殊寄存器中(在需要时将其推送到堆栈)。所以这个错误的程序不会崩溃是正常的。
更新:此外,在某些系统堆栈上长大(到更高的地址)。至少在ARM堆栈中,可以选择增长。