C语言使用strncpy()触发缓冲区溢出的内存行为疑问
strncpy缓冲区溢出现象答疑
复现代码
#include<stdio.h> #include<string.h> int main(){ char arr1[]="Buffer overflow"; char arr2[5]; printf("Size of array1 %d\n",sizeof(arr1)); strncpy(arr2,arr1,20); printf("\nAfter copy\n"); printf("Length of arr2: %d\n",strlen(arr2)); printf("Size of arr2: %d\n",sizeof(arr2)); printf("Arr2: %s\n",arr2); return 0; }
运行输出
Size of array1 16 After copy Length of arr2: 15 Size of arr2: 5 Arr2: Buffer overflow
核心原因拆解
不存在“5字节数组自动变长容纳内容”的情况,你观察到的矛盾现象本质是混淆了C语言的不同机制,同时触发了未定义的缓冲区溢出行为,具体逻辑如下:
1. 两个长度相关操作的本质完全不同
sizeof是编译期运算符,不是运行时函数。arr2声明为char[5]类型,它的大小在编译阶段就已经固定,代码里的sizeof(arr2)会被编译器直接替换为常量5,和运行时往对应内存写了什么内容毫无关系,所以输出永远是5。strlen是运行时库函数,它完全不知道传入的数组原本声明了多大,唯一的工作逻辑是:从传入的内存地址开始逐字节遍历,直到遇到第一个值为'\0'的字符串终止符就停止,返回遍历过的非0字节总数。
2. 你看到的“装下20字节”本质是缓冲区溢出
C语言本身不会在运行时做数组边界检查,你声明arr2[5]只是向编译器申请了5字节的合法访问空间,不代表写入超过5字节就会立刻被系统拦截。
程序运行时arr2被分配在栈内存上,它后面紧邻着其他可读写的栈空间(可能是其他临时变量、栈对齐填充位、保存的寄存器值等)。调用strncpy(arr2, arr1, 20)时,strncpy不会检查目标缓冲区的实际大小,只会从arr2的起始地址开始忠实地写入20字节:
- 前15字节写入
arr1存储的Buffer overflow字符 - 第16字节写入
arr1末尾自带的'\0'终止符 - 剩余4字节按照
strncpy的规则补填'\0'
从第6字节开始,写入的内容就已经超出了arr2的合法范围,覆盖了arr2后面的栈内存,这就是典型的栈缓冲区溢出,属于C标准明确规定的未定义行为。
后续调用strlen和printf输出字符串时,都是从arr2的起始地址开始遍历,直到第16位碰到写入的'\0'才停止,自然会得到15的长度值、输出完整的字符串。
注意事项
这次运行没有崩溃完全是概率事件:刚好越界写入的栈区域是可写的,没有覆盖栈保护校验值、函数返回地址等关键数据,也没有触发内存访问权限异常。这类越界代码没有任何可移植性,换编译选项(比如开启栈保护)、调整变量声明顺序、换编译器版本,都可能直接导致程序崩溃、输出乱码,甚至留下可被利用的安全漏洞。
另外需要注意:strncpy不是设计用来做安全字符串拷贝的函数,它不会自动校验目标缓冲区容量,当传入的拷贝长度超过缓冲区大小时,必然产生越界写入,本身就是C语言缓冲区溢出的高发诱因。
内容的提问来源于stack exchange,提问作者hari hara sankar
相关产品推荐
相关产品推荐

