C++字符串拷贝与缓冲区溢出
2015-04-11 16:23
253 查看
对于常用的字符串拷贝函数,常用的有:
Ansi版本如下:
strcpy, strncpy, strcpy_s, strncpy_s, StringCbCopy
Unicode版本为:
wcscpy,wcsncpy,wcsncpy_s,wcsncpy_s,StringCbCopyW
其中最后一个为Windows的API,其余为c运行时函数。
这些函数完成的功能是一样的,然而本质上却有极大区别。
现在我们来看看这些函数分别如何工作。
为简化测试,我们只测试Ansi版本的函数。Unicde版本功能与之如出一辙。
测试代码如下(VS2005,多字节编码):
[cpp] view
plaincopy
char buff1[2] = {'1', '/0'};
char buff2[2] = {'2', '/0'};
strcpy(buff1, "1111111111111111");
strncpy(buff2, "abcdefghijklmnopqratuvwxyz", 2);
StringCbCopy(buff2, 2, "abcdefghijklmnopqratuvwxyz");
strcpy_s(buff2, 2, "abcdefghijklmnopqratuvwxyz");
buff2的地址为0x22FE0C,内存分布如下图:
可以看到buff1和buff2之间被填充了0xcc,这是VS为了检测缓冲区运行时整的。
另外注意栈内存分配上的特点,后分配的buff2的地址在先分配的buff1地址之前。
现在执行strcpy,看内存变化:
strcpy强行把16字节写入了buff1为首的内存。然而系统没有任何反映,似乎一切正常。
然而,正式这种侥幸的正常,才会导致日后不可避免的缓冲区溢出导致的崩溃---谁知道buff1+2之后的14个字节是什么内容。
继续执行,看看strncpy的表现会不会好一点:
strncpy的第三个参数接收缓冲区大小,如果待拷贝字符串长度超过缓冲区,则截断超出的字符不拷贝。
这么做似乎很安全。然而致命的问题是这个“截断“太过劣质。
因为buff2失去了'/0'结束符,buff2字符串是从buff2开始直到之后内存中找到的第一个'/0'
在这里,由于buff2内存之后是buff1,buff2已经不再是2个字节的字符串了。缓冲区受到了破坏。
这个例子里,我们看到buff2的内容是形如"ab烫烫烫烫烫烫烫烫1111111111111111"这样的乱码
诚然,这样的操作也是极不安全的。
我们继续执行,看看StringCbCopy表现如何。
呼呼,我们终于看到一个表现堪称“不错”的字符串拷贝函数了。
她总算是“优美”的截断了过长的字符串,保证了缓冲区的安全性。
然而,这样的截断后的字符串是你需要的吗?比如一个路径名字符串被截断了,你还能用他来打开文件吗?
strcpy_s的第2个参数接收缓冲区大小。我们看看他执行结果如何:
饿...出现了assert错误。
不过这样对程序员来说应该是最好的,你很快能知道是哪里出了问题。
一般而言,凡是函数后面带有_s的字符串系列函数,都是微软整的“安全”字符串函数。
他会进行传入指针不为NULL、缓冲区足够大等等安全检查。
因此,我们在整字符串的时候,应该使用这些安全字符串。
最后请注意:上面所有函数都不进行内存重叠检查!请自己进行必要的内存重叠检查。
原文地址:http://blog.csdn.net/lsldd/article/details/4669888
Ansi版本如下:
strcpy, strncpy, strcpy_s, strncpy_s, StringCbCopy
Unicode版本为:
wcscpy,wcsncpy,wcsncpy_s,wcsncpy_s,StringCbCopyW
其中最后一个为Windows的API,其余为c运行时函数。
这些函数完成的功能是一样的,然而本质上却有极大区别。
现在我们来看看这些函数分别如何工作。
为简化测试,我们只测试Ansi版本的函数。Unicde版本功能与之如出一辙。
测试代码如下(VS2005,多字节编码):
[cpp] view
plaincopy
char buff1[2] = {'1', '/0'};
char buff2[2] = {'2', '/0'};
strcpy(buff1, "1111111111111111");
strncpy(buff2, "abcdefghijklmnopqratuvwxyz", 2);
StringCbCopy(buff2, 2, "abcdefghijklmnopqratuvwxyz");
strcpy_s(buff2, 2, "abcdefghijklmnopqratuvwxyz");
buff2的地址为0x22FE0C,内存分布如下图:
可以看到buff1和buff2之间被填充了0xcc,这是VS为了检测缓冲区运行时整的。
另外注意栈内存分配上的特点,后分配的buff2的地址在先分配的buff1地址之前。
现在执行strcpy,看内存变化:
strcpy强行把16字节写入了buff1为首的内存。然而系统没有任何反映,似乎一切正常。
然而,正式这种侥幸的正常,才会导致日后不可避免的缓冲区溢出导致的崩溃---谁知道buff1+2之后的14个字节是什么内容。
继续执行,看看strncpy的表现会不会好一点:
strncpy的第三个参数接收缓冲区大小,如果待拷贝字符串长度超过缓冲区,则截断超出的字符不拷贝。
这么做似乎很安全。然而致命的问题是这个“截断“太过劣质。
因为buff2失去了'/0'结束符,buff2字符串是从buff2开始直到之后内存中找到的第一个'/0'
在这里,由于buff2内存之后是buff1,buff2已经不再是2个字节的字符串了。缓冲区受到了破坏。
这个例子里,我们看到buff2的内容是形如"ab烫烫烫烫烫烫烫烫1111111111111111"这样的乱码
诚然,这样的操作也是极不安全的。
我们继续执行,看看StringCbCopy表现如何。
呼呼,我们终于看到一个表现堪称“不错”的字符串拷贝函数了。
她总算是“优美”的截断了过长的字符串,保证了缓冲区的安全性。
然而,这样的截断后的字符串是你需要的吗?比如一个路径名字符串被截断了,你还能用他来打开文件吗?
strcpy_s的第2个参数接收缓冲区大小。我们看看他执行结果如何:
饿...出现了assert错误。
不过这样对程序员来说应该是最好的,你很快能知道是哪里出了问题。
一般而言,凡是函数后面带有_s的字符串系列函数,都是微软整的“安全”字符串函数。
他会进行传入指针不为NULL、缓冲区足够大等等安全检查。
因此,我们在整字符串的时候,应该使用这些安全字符串。
最后请注意:上面所有函数都不进行内存重叠检查!请自己进行必要的内存重叠检查。
原文地址:http://blog.csdn.net/lsldd/article/details/4669888
相关文章推荐
- C++字符串拷贝与缓冲区溢出
- C++ 字符串拷贝 汇编代码实现
- C++面试题之字符串的拷贝
- 关注C++细节——字面值初始化字符数组及字符串拷贝注意
- 面试C++题目,字符串拷贝与小写换大写
- C/C++字符串,字符数组,字符指针及其相互静态拷贝与追加的安全问题解决方案(2)
- C/C++字符串,字符数组,字符指针及其相互静态拷贝与追加的安全问题解决方案(1)
- C/C++实现字符串拷贝和截取
- 请用c++ 实现stl中的string类,实现构造,拷贝构造,析构,赋值,比较,字符串相加,获取长度及子串等功能
- 请用c++ 实现stl中的string类,实现构造,拷贝构造,析构,赋值,比较,字符串相加,获取长度及子串等功能。
- C++内存问题大集合(指针问题,以及字符串拷贝问题,确实挺危险的)
- C++字符串一个简单的拷贝
- C/C++--字符串拷贝及内存操作(转载)
- c++字符串拷贝几个方法浅析sprintf,strcpy及memcpy
- C++学习笔记(字符串string、vector_deque、queue,multiset、map、multimap、容器拷贝问题)
- c++实现字符串的深拷贝
- 关注C++细节——字面值初始化字符数组及字符串拷贝注意
- C++字符串拷贝实现:递归方法&非递归方法
- C++ 16 拷贝字符串
- C/C++--字符串拷贝及内存操作(转载)