为什么向2字节栈缓冲区写入3字节时GCC和Valgrind均不报错?
问题原因解答
1. GCC无警告的原因
-Wall -Wextra 编译参数默认不会启用静态缓冲区溢出检测逻辑,GCC仅在开启 -Warray-bounds 编译选项且配合 -O1 及以上优化等级时,才会对编译期可识别的数组越界操作输出警告。
你代码中memcpy的拷贝长度是运行时通过strlen(x1)计算得到的,默认静态检查不会深入推导运行时的长度取值,因此不会触发警告。
2. Valgrind默认无报错的原因
你默认使用的Valgrind Memcheck工具,检测范围仅覆盖堆内存(即malloc/realloc/free等动态分配的内存)的越界访问、内存泄漏、非法释放等问题。
你代码中的in_buffer和x1都是栈上分配的局部变量,你越界写入的1字节刚好落在当前函数栈帧内部的x1数组存储空间内,这部分地址属于进程合法可访问的栈空间:
- 操作系统不会触发段错误
- Memcheck不会将其识别为非法内存访问,因此没有报错
如果需要检测栈/全局数组的越界问题,可以使用Valgrind的SGCheck实验性工具,运行命令为valgrind --tool=exp-sgcheck ./a.out,即可检测到本次栈越界错误。
3. 代码存在的实际风险
这段代码属于典型的栈缓冲区溢出,是C语言标准明确的未定义行为,当前无报错不代表逻辑合法:
- 你运行输出的
abcbc已经是异常结果:memcpy写入3字节到仅2字节的in_buffer后,in_buffer末尾没有字符串终止符\0,printf读取字符串时会一直向后遍历相邻的x1存储区域,直到遇到\0才停止,因此输出了超出预期的内容。 - 该未定义行为在不同编译环境、不同系统上表现完全不确定,可能直接崩溃、可能输出异常内容,极端场景下会被利用进行栈溢出攻击。
内容的提问来源于stack exchange,提问作者user786
相关产品推荐
相关产品推荐

