可能重复:
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
而不会崩溃。为什么这样做?
答案 0 :(得分:8)
仅仅因为你写入未分配的内存并不意味着程序会崩溃。没有像这样的运行时边界检查。
当您通过硬件检测到的通过操作系统分配的地址范围访问内存时,将发生段错误。在此之前,您可能会在堆中获得大量内存访问权。
答案 1 :(得分:6)
写入太小的缓冲区是未定义的行为。没有保证它会崩溃。它可能不会崩溃。它似乎可行。它也可能会默默地破坏某些数据。它可能会导致程序无意中执行某些操作 - 当攻击者将未定义行为的影响转换为不需要的行为时,会出现许多安全漏洞。通过严格阅读标准,这甚至可以起到召唤恶魔的作用。
在建筑层面,通常分配被四舍五入到两个幂(但这无论如何都无法保证!),因此为什么你在这里看不到任何明显不好的东西。但不依赖于此,因为它可以而且确实有所不同。
答案 2 :(得分:4)
malloc
实现可以并且经常会分配比您要求的更多的内存。大多数实现将向上舍入到最接近的8或16字节的倍数。
答案 3 :(得分:2)
硬件内存管理器控制完整的内存页面,通常为4K。除非您的写入溢出页边界,否则内存管理硬件不会生成SEGFAULT / Access Violation中断。
您的示例“有效”,因为大量“未定义行为”中的一个元素“看起来正常工作,至少现在是这样”。如果您为应用添加了复杂性,该套装的其他成员将会显示...
答案 4 :(得分:1)
这意外地起作用。您的malloc可能会分配比单个字符大得多的块(通常因为跟踪纳米级片段不值得花费)。因此,您可能会在您应该拥有的空间之外进行操控,但这与您的实施无关。
根据标准,我认为您的计划仍然是错误的。如果它更大,并且你在意外无法工作的地方犯了错误,你会得到各种不良行为,有时是非法的记忆访问,但有时只是完全疯狂的行为,因为你可能会损坏你的或系统数据结构。
我们的CheckPointer测试工具应该能够发现此错误;从技术上讲,你存储在你所要求的区域之外,并且可以通过足够的努力来检测。