空字符是否会触发栈溢出?栈溢出检测特殊行为咨询
栈溢出检测中空字符的特殊行为分析
测试场景与现象
测试GCC的-f-stack-protector栈溢出检测机制时发现:向字符缓冲区末尾外写入空字符'\0'不会触发栈溢出提示,但写入其他字符则会触发。
测试代码(开启-f-stack-protector编译):
#include <stdio.h> int main(int argc, char *argv[]) { char buf[8]; char c; printf("Enter a string: "); int i; for (i = 0; (c = getchar()) != '\n'; i++) buf[i] = c; buf[i] = '\0'; printf("string = [%s]\n", buf); return 0; }
测试现象:
- 输入9个字符时,程序正常弹出
*** stack smashing detected ***: terminated提示; - 输入8个字符时,
buf[8] = '\0'会写入缓冲区外,但无任何检测提示; - 若将代码中的
'\0'替换为其他字符(如'A'),输入8个字符时会触发检测。
原因分析
这并非异常行为,而是-f-stack-protector机制的设计特性:
- 栈金丝雀的原理:该机制会在栈上的缓冲区与返回地址之间插入一个随机生成的「栈金丝雀(canary)」值,程序退出前会检查金丝雀是否被篡改,若值被改变则判定为栈溢出并触发提示。
- 金丝雀的设计细节:GCC默认生成的栈金丝雀值低位字节固定为0,这是为了兼容C语言中字符串以
'\0'结尾的特性——避免正常的字符串终止操作(如在缓冲区末尾外意外写入'\0')误触发栈溢出检测。 - 对应场景的解释:
- 输入8个字符时,循环结束后
i=8,buf[8] = '\0'写入的位置恰好是栈金丝雀的低位字节,而该字节原本就是0,所以金丝雀值未被篡改,检测机制不触发; - 输入9个字符时,循环中会向
buf[8]写入输入的第9个字符(非0),直接破坏金丝雀值,后续检查时就会触发栈溢出提示; - 若将
'\0'替换为'A'(0x41),写入金丝雀位置时会改变其值,因此触发检测。
- 输入8个字符时,循环结束后
内容的提问来源于stack exchange,提问作者jayer
相关产品推荐
相关产品推荐

