字符数组栈溢出检测疑问:为何写入7字节未触发告警?
栈溢出检测为何未在写入7字节时触发?
我尝试使用string.h中的strcat拼接字符串str1和str2。目标字符串str1在栈上占用6字节,按预期写入超过6字节的内容应触发“stack smashing detected”告警,但实际写入7字节(12345,6,NUL)时未触发该告警,仅在写入8字节(12345,67,NUL)时触发。已知strcat在目标空间不足时属于未定义行为,但想了解为何这会影响栈溢出检测。
编译环境:gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
#include <stdio.h> #include <string.h> int main() { char str1[6] = "12345"; char* str2 = "6"; // 运行正常,但原因是什么? //char* str2 = "67"; // 触发“*** stack smashing detected ***: terminated” strcat(str1, str2); return 0; }
原因解析
GCC默认启用的栈溢出检测依赖金丝雀(Canary)机制:编译器会在栈帧的返回地址附近插入一个随机生成的特殊标记值。函数返回前会校验该值,若被篡改则触发栈溢出告警。
具体到你的代码:
- 拼接
"6"时,strcat需要写入6和新的终止符\0,合计2字节。str1原本的终止符\0会被覆盖,随后越界写入1字节(新的\0)。这1字节的越界刚好落在金丝雀值之前的栈空白区域(比如编译器为变量分配的对齐空间、未被使用的相邻栈内存),没有触及金丝雀值,因此检测机制不会触发。 - 拼接
"67"时,strcat需要写入6、7和\0,合计3字节,越界写入2字节。这会直接覆盖到金丝雀值的位置,导致返回前的校验失败,触发告警。
需要注意的是,栈布局由编译器的优化、对齐规则等决定,未定义行为的表现本身不可预测——换个编译环境或选项,7字节写入也可能触发告警,这正是未定义行为的典型特征。
内容的提问来源于stack exchange,提问作者Electrix
相关产品推荐
相关产品推荐

