简体   繁体   English

malloc()和堆内存

[英]malloc() and heap memory

I am getting a strange result in the following C code. 我在以下C代码中得到一个奇怪的结果。

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

Since I have allocated only 100 bytes, this code should give cause a segmentation fault. 由于我只分配了100个字节,因此该代码应该导致分段错误。 However, it prints '5' and does not give any runtime error. 但是,它打印'5'并且不会给出任何运行时错误。 Can anyone please explain the reason? 有人可以解释原因吗?

No, the code should not (necessarily) give a segfault. 不,代码不应该(必然)给出段错误。 A segfault occurs when you attempt to access a virtual memory page that is not allocated to your process. 当您尝试访问未分配给您的进程的虚拟内存页时,会发生段错误。

The "heap" or "free store" is a region of virtual memory pages owned by your process. “堆”或“免费存储”是您的进程拥有的虚拟内存页面区域。 The malloc() API sub-divides this region into blocks and returns a pointer to the block. malloc() API将此区域细分为块,并返回指向块的指针。

If you address beyond the end of the block to which you have a pointer, you will usually access memory that is part of the heap, but not part of your allocated block. 如果超出了具有指针的块的末尾,则通常会访问作为堆的一部分的内存,但不会访问已分配块的内存。 In this way, you can corrupt other heap blocks or even the data structures which malloc() uses to define the heap. 通过这种方式,您可以破坏其他堆块甚至是malloc()用于定义堆的数据结构。

For more information on heap corruption, and methods to detect it in the debug version of your code, this is a great book: 有关堆损坏的更多信息,以及在代码的调试版本中检测它的方法,这是一本很棒的书:

Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire 编写固体代码:微软的Steve Maguire开发无错误C程序的技术 替代文字

An addendum for the pedantic: In rare cases, by accessing memory beyond the end of a heap block, you may access memory that is not part of the heap. 迂腐的附录:在极少数情况下,通过访问堆块末尾之外的内存,您可以访问不属于堆的内存。 In these cases, you may get the segmentation fault you expected. 在这些情况下,您可能会遇到预期的分段错误。 You might also corrupt some other data structure than the heap. 您还可能损坏堆之外的其他一些数据结构。 It's really a matter of chance. 这真是一个偶然的问题。 However, the heap itself is very large compared to typical heap blocks, so 99% of the time code such as your example will corrupt the heap. 但是,与典型的堆块相比,堆本身非常大,因此99%的时间代码(例如您的示例)将损坏堆。 The example you provide falls into that 99% case. 您提供的示例属于99%的情况。

Invalid memory accesses won't always cause a segmentation fault, bus error, or other crash. 无效的内存访问不会总是导致分段错误,总线错误或其他崩溃。 For example, if there's another block allocated immediately after your array, you're changing the values in that block -- which could be anything. 例如,如果你的阵列之后分配另一个块,你改变块中的价值-它可以是任何东西。

No, it can give a segfault, but only if the memory is outside your process. 不,它可以提供段错误,但前提是内存不在您的进程中。 Otherwise it will just modify some other area of your program memory. 否则它只会修改程序存储器的其他区域。 C doesn't check for this, or protect you in any way, even in obvious cases like the above. C不会检查这一点,或以任何方式保护您,即使在如上所述的明显情况下也是如此。 Many many software crackers use this "feature" of C to essentially rewrite a program that has elevated privs, and give themselves control over your machine. 许多软件破解程序使用C的这个“功能”来基本上重写具有提升的priv的程序,并让自己控制你的机器。 It is called a buffer overflow exploit . 它被称为缓冲区溢出漏洞

This is why C (and C++) should really be avoided for new software in preference for safer languages like Ada. 这就是为什么C(和C ++)应该真正避免使用新软件,而不是像Ada这样更安全的语言。

You are writing into memory which you have not allocated. 您正在写入尚未分配的内存。 The program might eventually terminate due to the effects of heap corruption if its run time were sufficiently long. 如果运行时间足够长,程序最终可能会因堆损坏的影响而终止。

You're writing to uninitialized memory; 你正在写未初始化的记忆; this is allowed in C, it's just not a good idea. 这在C中是允许的,这不是一个好主意。 This sort of thing shouldn't necessarily cause a segmentation fault. 这种事情不一定会导致分段错误。

Common causes of segmentation fault: 分段错误的常见原因:

  • dereferencing pointer with invalid value 取消引用具有无效值的指针
  • dereferencing null pointers 解除引用空指针
  • attempting to write into a read-only segment 试图写入只读段
  • free-ing improper pointers or un-owned blocks. 释放不正确的指针或不拥有的块。

    int *x=0; int * x = 0;

    x = 200; x = 200; / causes segmentation fault */ /导致分段错误* /

Segfaults are generated by MMU exceptions based on what is determined to be an illegal memory access. 基于确定为非法内存访问的MMU异常生成段错误。 Depending on how the OS structures its memory, one memory access on an OS might be legal (although wrong) and on another OS it might be illegal. 根据操作系统如何构建其内存,操作系统上的一个内存访问可能是合法的(尽管是错误的),而在另一个操作系统上,它可能是非法的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM