为什么执行这个操作没有导致分段错误?

4
我有如下代码:

可能会重复:
无效的读写有时会导致分割错误,有时不会

代码如下:

#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而不会崩溃。为什么会这样呢?


1
你可能想要查看这个问题及其答案以获取指导:http://stackoverflow.com/questions/8641478/invalid-read-write-sometimes-creates-segmentation-fault-and-sometimes-does-not - Dan Fego
我知道 sizeof(char) 总是1。我只是想尝试一下以确定工作的基本原理。 - Alex Reynolds
4
触发未定义行为的美妙之处在于任何事情都可能发生,而且这是“可以接受的”——所需的行为是未定义的。 - Jonathan Leffler
1
如果您有答案,我将不胜感激,如果您能尝试将它们作为答案而不是评论添加。 - Alex Reynolds
如果您要点踩,请花时间评论一下原因。 - Alex Reynolds
显示剩余2条评论
5个回答

8

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

当硬件检测到您正在访问超出操作系统分配地址范围的内存时,将会发生段错误。在堆中进行许多内存访问之前,您可能会摆脱这种情况。


6
向一个过小的缓冲区写入数据是未定义的行为。没有保证它会崩溃。它可能不会崩溃。它可能表现正常。它也可能悄悄地破坏一些数据。它可能导致程序执行意外操作 - 许多安全漏洞都源于此,当攻击者将未定义行为的效果操纵成不希望的结果时。按照标准的严格解释,这甚至可能导致从你的鼻子召唤恶魔的效果。
在架构层面上,通常分配会被舍入到2的某个幂次方(但这并不被任何方式保证!),因此你在这里没有看到任何明显的异常。但是不要依赖于此,因为它可能会变化。

4
< p > malloc 实现通常会比您请求的内存多分配一些内存。 大多数实现将至少向最接近的 8 或 16 字节的倍数舍入。 < / p >

2

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

您的示例“有效”,因为“未定义行为”大集合中的一个元素是“看起来正确运行,至少现在是这样的”。如果您向应用程序添加复杂性,集合的其他成员将出现...


1

这个偶然起作用了。你的malloc可能分配了一个比单个字符大得多的块(通常是因为跟踪纳米级碎片不值得开销)。所以你很可能会跨越你应该拥有的空间,但在你的实现中并没有关系。

我认为,根据标准,你的程序仍然存在错误。如果它更大,并且你在那些不起作用的地方犯了这个错误,你会得到各种各样的不良行为,有时是非法内存访问,但有时只是完全疯狂的行为,因为你可以损坏你的或系统数据结构。

我们的CheckPointer测试工具应该能够发现这个错误;从技术上讲,你正在存储超出你请求的区域,这是可以通过足够的努力检测到的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接