malloc()和堆内存

时间:2009-11-17 19:53:35

标签: c memory

我在以下C代码中得到了一个奇怪的结果。

int main()
{
    int *p = (int *) malloc(100);
    p[120] = 5;
    printf("\n %d", p[120]);
}

由于我只分配了100个字节,因此该代码应该导致分段错误。但是,它打印'5'并且不会给出任何运行时错误。有人可以解释原因吗?

6 个答案:

答案 0 :(得分:20)

不,代码不应该(必然)给出段错误。当您尝试访问未分配给您的进程的虚拟内存页时,会发生段错误。

“堆”或“免费商店”是您的流程拥有的虚拟内存页面区域。 malloc() API将此区域细分为块,并返回指向块的指针。

如果超出了指针所在块的末尾,则通常会访问作为堆的一部分的内存,但不会访问已分配块的内存。通过这种方式,您可以破坏其他堆块甚至malloc()用于定义堆的数据结构。

有关堆损坏的更多信息,以及在代码的调试版本中检测它的方法,这是一本很棒的书:

Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire alt text

迂腐的附录:在极少数情况下,通过访问堆块末尾之外的内存,您可以访问不属于堆的内存。在这些情况下,您可能会遇到预期的分段错误。您还可能损坏堆之外的其他一些数据结构。这真是一个偶然的问题。但是,与典型的堆块相比,堆本身非常大,因此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。根据操作系统如何构建其内存,操作系统上的一个内存访问可能是合法的(尽管是错误的),而在另一个操作系统上,它可能是非法的。