程序不会在堆溢出时崩溃
我写了以下程序:
#include #include #include void main(int argc, char *argv[]){ char *input; input = (char*)malloc(16); printf("input is : %s\n", 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 : %s\n", input); }
Python脚本提供的内容无关紧要。 但是,你的printf()
正在打印未初始化的数据; 这会导致不确定的行为。 如果printf()
没有崩溃并且有free(input);
在printf()
之后调用,然后free()
不应该崩溃。
如果您错过了复制操作并打算显示类似的内容,那么规则就不同了:
int main(int argc, char *argv[]){ char *input; input = (char*)malloc(16); strcpy(input, argv[1]); printf("input is : %s\n", input); free(input); return 0; }
现在你没有在使用它之前检查argv[1]
是不是空指针 – 这可能会导致崩溃。 如果你在argv[1]
传递5000个字符,那么你正在践踏分配内存的界限。 有些东西可能会引发撞车; 它没有定义会导致崩溃的原因。 strcpy()
可能会失败; 如果副本没有(但不保证), printf()
可能不会失败; free()
可能会失败,因为你践踏了界限(但即使这样也无法保证)。 这就是“未定义行为”的奇迹; 任何事都可能发生,这是有效的行为。
为什么会这样?
缓冲区溢出(在这种情况下是堆溢出 )不会立即导致崩溃。 在分配的内存范围之外写入会导致未定义的行为 – 任何可能发生的事情; 即使它可以正常工作。
有没有free()创建崩溃的可靠方法
如果你甚至没有初始化指针input
并取消引用它(在那里读或写), 很可能你会得到一个SEGFAULT,但它仍然是’仅’未定义的行为。
来自C99标准草案
可能的未定义行为包括完全忽略不完整结果的情况 ,在翻译或程序执行期间以环境特征(有或没有发出诊断消息)的特定文档执行,终止翻译或执行(发布时)一条诊断信息)。
但要小心
溢出可能会导致任何使用受影响的内存区域的进程出现数据损坏或意外行为。 在没有内存保护的操作系统上,这可能是系统上的任何进程。