为什么运行它不会发出分段错误?

时间:2012-01-01 21:55:30

标签: c memory gcc malloc

  

可能重复:
  Invalid read/write sometimes creates segmentation fault and sometimes does not

我有以下代码:

#include <stdlib.h>
#include <stdio.h>

int main() {
    int *ptr = NULL;
    ptr = malloc(sizeof(char));
    if (ptr) {
        *ptr = 10;
        printf("sizeof(int): %zu\nsizeof(char): %zu\n", sizeof(int), sizeof(char));
        printf("deref of ptr: %d\n", *ptr);
        free(ptr);
        return EXIT_SUCCESS;
    }
    else
        return EXIT_FAILURE;
}

当我编译并运行它时,我得到以下输出:

$ gcc test.c
$ ./a.out 
sizeof(int): 4
sizeof(char): 1
deref of ptr: 10

sizeof(char)小于sizeof(int)。我的malloc来电仅为char留出足够的空间。然而,我的程序能够将整数值分配给ptr而不会崩溃。为什么这样做?

5 个答案:

答案 0 :(得分:8)

仅仅因为你写入未分配的内存并不意味着程序会崩溃。没有像这样的运行时边界检查。

当您通过硬件检测到的通过操作系统分配的地址范围访问内存时,将发生段错误。在此之前,您可能会在堆中获得大量内存访问权。

答案 1 :(得分:6)

写入太小的缓冲区是未定义的行为。没有保证它会崩溃。它可能不会崩溃。它似乎可行。它也可能会默默地破坏某些数据。它可能会导致程序无意中执行某些操作 - 当攻击者将未定义行为的影响转换为不需要的行为时,会出现许多安全漏洞。通过严格阅读标准,这甚至可以起到召唤恶魔的作用。

在建筑层面,通常分配被四舍五入到两个幂(但这无论如何都无法保证!),因此为什么你在这里看不到任何明显不好的东西。但不依赖于此,因为它可以而且确实有所不同。

答案 2 :(得分:4)

malloc实现可以并且经常会分配比您要求的更多的内存。大多数实现将向上舍入到最接近的8或16字节的倍数。

答案 3 :(得分:2)

硬件内存管理器控制完整的内存页面,通常为4K。除非您的写入溢出页边界,否则内存管理硬件不会生成SEGFAULT / Access Violation中断。

您的示例“有效”,因为大量“未定义行为”中的一个元素“看起来正常工作,至少现在是这样”。如果您为应用添加了复杂性,该套装的其他成员将会显示...

答案 4 :(得分:1)

这意外地起作用。您的malloc可能会分配比单个字符大得多的块(通常因为跟踪纳米级片段不值得花费)。因此,您可能会在您应该拥有的空间之外进行操控,但这与您的实施无关。

根据标准,我认为您的计划仍然是错误的。如果它更大,并且你在意外无法工作的地方犯了错误,你会得到各种不良行为,有时是非法的记忆访问,但有时只是完全疯狂的行为,因为你可能会损坏你的或系统数据结构。

我们的CheckPointer测试工具应该能够发现此错误;从技术上讲,你存储在你所要求的区域之外,并且可以通过足够的努力来检测。