我在以下C代码中得到了一个奇怪的结果。
int main()
{
int *p = (int *) malloc(100);
p[120] = 5;
printf("\n %d", p[120]);
}
由于我只分配了100个字节,因此该代码应该导致分段错误。但是,它打印'5'并且不会给出任何运行时错误。有人可以解释原因吗?
答案 0 :(得分:20)
不,代码不应该(必然)给出段错误。当您尝试访问未分配给您的进程的虚拟内存页时,会发生段错误。
“堆”或“免费商店”是您的流程拥有的虚拟内存页面区域。 malloc()
API将此区域细分为块,并返回指向块的指针。
如果超出了指针所在块的末尾,则通常会访问作为堆的一部分的内存,但不会访问已分配块的内存。通过这种方式,您可以破坏其他堆块甚至malloc()
用于定义堆的数据结构。
有关堆损坏的更多信息,以及在代码的调试版本中检测它的方法,这是一本很棒的书:
Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire
迂腐的附录:在极少数情况下,通过访问堆块末尾之外的内存,您可以访问不属于堆的内存。在这些情况下,您可能会遇到预期的分段错误。您还可能损坏堆之外的其他一些数据结构。这真是一个偶然的问题。但是,与典型的堆块相比,堆本身非常大,因此99%的时间代码(例如您的示例)将损坏堆。您提供的示例属于99%的情况。
答案 1 :(得分:6)
无效的内存访问不会总是导致分段错误,总线错误或其他崩溃。例如,如果在您的数组之后立即分配了另一个块,则您将更改 块中的值 - 这可能是任何内容。
答案 2 :(得分:3)
不,可以提供段错误,但前提是内存不在您的进程中。否则它只会修改程序存储器的其他区域。 C不会检查这一点,或以任何方式保护您,即使在如上所述的明显情况下也是如此。许多软件破解程序使用C的这个“功能”来基本上重写具有提升的priv的程序,并让自己控制你的机器。它被称为buffer overflow exploit。
这就是为什么新软件应该首先避免使用C(和C ++),而不是像Ada这样更安全的语言。
答案 3 :(得分:0)
您正在写入尚未分配的内存。如果运行时间足够长,程序最终可能会因堆损坏的影响而终止。
答案 4 :(得分:0)
你正在写未初始化的记忆;这在C中是允许的,这不是一个好主意。这种事情不应该导致分段错误。
答案 5 :(得分:0)
分段错误的常见原因:
释放不正确的指针或非拥有的块。
int * x = 0;
x = 200; / 导致分段错误* /
根据确定为非法内存访问的内容,MMU异常会生成Segfaults。根据操作系统如何构建其内存,操作系统上的一个内存访问可能是合法的(尽管是错误的),而在另一个操作系统上,它可能是非法的。