我写了以下程序:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(int argc, char *argv[]){
char *input;
input = (char*)malloc(16);
printf("input is : %sn", input);
}
当我运行时:
./test `python -c 'print "A"*5000'`
它不会崩溃。它宁愿打印数据。
当我在printf
之后使用free(input)
时,它会崩溃。
为什么会发生这种情况?
所示代码忽略其命令行参数:
int main(int argc, char *argv[]){
char *input;
input = (char*)malloc(16);
printf("input is : %sn", input);
}
Python脚本提供的内容无关紧要。但是,您的printf()
正在打印非初始化的数据;这导致了不确定的行为。如果printf()
没有崩溃,并且在printf()
之后有free(input);
调用,则free()
不应崩溃。
如果您错过了副本操作并打算显示这样的内容,则规则是不同的:
int main(int argc, char *argv[]){
char *input;
input = (char*)malloc(16);
strcpy(input, argv[1]);
printf("input is : %sn", input);
free(input);
return 0;
}
现在,您没有在使用之前检查argv[1]
不是零指针,而是可能导致崩溃。如果您在argv[1]
中传递了5000个字符,则您将践踏分配的内存的界限。某些东西可能会触发崩溃;没有定义什么会导致崩溃。strcpy()
可能会失败;printf()
可能不会失败,如果副本没有(但不能保证);free()
可能会失败,因为您从范围中踩踏了(但这也不能保证)。这就是"不确定行为"的奇观;一切都可能发生,这是有效的行为。
为什么会发生这种情况?
缓冲区溢出(在这种情况下,堆溢出)不会立即崩溃。在分配记忆的范围之外写作会导致不确定的行为 - 任何事情都可能发生;即使它也可以正常工作。
是否有一种可靠的方法来创建崩溃而没有免费()
如果您甚至不初始化指针input
并将其取消(读或写入),最有可能您会得到一个segfault,但它仍然是"仅"未定义的行为。
来自C99标准草案
可能的未定义行为范围从忽略情况范围 完全具有不可预测的结果,在翻译过程中行为 或以记录的方式执行程序的特征 环境(有或没有发出诊断信息), 终止翻译或执行(发行 诊断消息)。
,但要小心
溢出可能会导致数据损坏或使用受影响的内存区域的任何过程。在没有内存保护的操作系统上,这可能是 System 的任何过程。