可能的重复项:
无效的读/写有时会造成分段错误,有时不会
我有以下代码:
#include <stdlib.h>
#include <stdio.h>
int main() {
int *ptr = NULL;
ptr = malloc(sizeof(char));
if (ptr) {
*ptr = 10;
printf("sizeof(int): %zunsizeof(char): %zun", sizeof(int), sizeof(char));
printf("deref of ptr: %dn", *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
分配一个整数值而不会崩溃。为什么会这样?
仅仅因为您正在写入未分配的内存并不意味着程序会崩溃。没有像那样的运行时边界检查。
当您访问的内存超出硬件检测到的通过操作系统分配的地址范围时,将发生段错误。在此之前,您可能会在堆中进行大量内存访问。
写入太小的缓冲区是未定义的行为。不能保证它会崩溃。它可能不会崩溃。它可能看起来有效。它还可能会以静默方式损坏某些数据。它可能会导致您的程序执行意外操作 - 当攻击者将未定义行为的效果操纵成不需要的内容时,许多安全漏洞都来自此。通过严格阅读标准,这甚至可能具有从鼻子中召唤恶魔的效果。
在架构级别,通常分配四舍五入到2的幂(但这无论如何都不能保证!(,因此为什么你在这里没有看到任何明显的不愉快。但不要依赖这一点,因为它可以而且确实会有所不同。
malloc
实现可以而且通常会分配比您请求的更多的内存。大多数实现将至少向上舍入到最接近的 8 或 16 字节的倍数。
硬件内存管理器控制完整的内存页,通常是 4K。 除非写入内容溢出页面边界,否则内存管理硬件不会生成 SEGFAULT/访问冲突中断。
您的示例"有效",因为大量"未定义行为"中的一个元素"看起来正常工作,至少目前是这样"。 如果增加应用的复杂性,则会显示集合中的其他成员...
意外的。 您的malloc可能会分配一个比单个字符大得多的块(通常是因为跟踪纳米级碎片不值得开销(。 因此,您可能会在应该拥有的空间之外踩踏,但这在您的实现中并不重要。
我认为,根据标准,您的程序仍然是错误的。 如果它大得多,并且你在它没有意外工作的地方犯了这个错误,你会得到各种不良行为,有时是非法的内存访问,但有时只是完全疯狂的行为,因为你可能会损坏你或系统数据结构。
我们的CheckPointer 测试工具应该能够发现此错误;从技术上讲,您存储在您请求的区域之外,并且可以通过足够的努力检测到。