Strsafe.h:更安详的C语言字符串处理惩罚函数
副标题#e#
原文出处:Strsafe.h: Safer String Handling in C:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/strsafe.asp
在微软公司进行的Microsoft Windows Security Push 勾当期间,一批测试者、措施打点司理和普通措施员配合抉择要为 C 语言量身定制一套具有较高安详性的字符串处理惩罚函数,而且但愿这些函数能被 Windows 措施员和微软公司内部的措施员所回收。
简朴说来,现有的 C 语言运行时函数实在难以在当今充斥着恶意进攻诡计的大情况下驻足。这些函数要么在返回值和参数上缺乏一致性,要么隐含着所谓的“截断误差”(truncation errors) 错误,要么无法提供足够强大的成果。坦言之,挪用这些函数的代码太容易发生“内存溢出”问题了。
我们发明,面向 C++ 措施员的类足以应付各类安详处理惩罚字符串的编程需要;他们可以或许选择 MFC 的Cstring 类、ATL 的CComBSTR 类 可能STL 的string 类,等等。然而,经典的 C 语言措施仍然普各处存在,况且很多人正在把 C++ 看成 “改善的 C 语言” 来用,却把富厚的 C++ 类束之高阁。
其实只需要添加一行代码,你就能在 C 语言代码中挪用安详性精采的 strsafe 系列函数了,具体请参阅:
《Using the Strsafe.h Functions》:http://msdn.microsoft.com/en-us/library/ms647466.aspx
这些新函数包括在一个头文件和一个函数库(可选)中,尔后两者能在新版的 Platform SDK 中找到。对,就这么简朴:
#include "strsafe.h"
还等什么呢!
再强调一次,对 strsafe 函数库的引用是可选的。
为了实现 strsafe 系列函数的方针,你的代码必需满意下列条件:
始终以 NULL 字符竣事字符串。
始终检测方针缓冲区的长度。
始终用 HRESULT 语句发生统一的返回值。
分身 32 位与 64 位两种运行情况。
具有机动性。
我们以为,缺乏统一性是导致现有很多 C 语言字符串处理惩罚函数容易发生安详裂痕的基础原因,而 strsafe 系列函数所带来的高度统一性恰恰是办理此问题的一剂良药。然而,strsafe 也不是万能药。纯真依靠 strsafe 系列函数并不能担保代码的安详性和健壮性——你还必需开动你的大脑才行——然而这样对办理问题照旧大有辅佐的!
下面给出一段回收经典 C 语言运行时间函数的代码:
void UnsafeFunc(LPTSTR szPath,DWORD cchPath) {
TCHAR szCWD[MAX_PATH];
GetCurrentDirectory(ARRAYSIZE(szCWD), szCWD);
strncpy(szPath, szCWD, cchPath);
strncat(szPath, TEXT("\\"), cchPath);
strncat(szPath, TEXT("desktop.ini"),cchPath);
}
#p#副标题#e#
以上代码中的 bug 到处可见 —— 它没有查抄任何一个返回值,并且在对 strncat 函数的挪用中也没有正确地利用 cchPath (因为MAX_PATH 中生存的是方针缓冲区内剩余空间的长度,而不是方针缓冲区的总长度)。于是,“内存溢出” 问题将会快找上门来。然而,象这样的代码片断早已泛滥成灾了。假如改用 strsafe 系列函数,那么以上代码应该酿成:
bool SaferFunc(LPTSTR szPath,DWORD cchPath) {
TCHAR szCWD[MAX_PATH];
if (GetCurrentDirectory(ARRAYSIZE(szCWD), szCWD) &&
SUCCEEDED(StringCchCopy(szPath, cchPath, szCWD)) &&
SUCCEEDED(StringCchCat(szPath, cchPath, TEXT("\\"))) &&
SUCCEEDED(StringCchCat(szPath, cchPath, TEXT("desktop.ini")))) {
return true;
}
return false;
}
这段代码不单查抄了每一个返回值,还担保了当令传入同一方针缓冲区的总长度。你还可以回收 Ex 版本的 strsafe 系列函数来实现越发高级的成果,好比:
获取方针缓冲区的当前指针。
获取方针缓冲区的剩余空间长度。
以某个特定字符填充空闲缓冲区。
一旦字符串处理惩罚函数失败,就把用特定值填充字符串。
一旦字符串处理惩罚函数失败,就把方针缓冲区设成 NULL 。
如此改造后的代码机能又如何呢?汇报你一个好动静:它与原先的代码在机能上险些没有不同。我曾在本身的 1.8 GHz 电脑上测试过混用经典 C 语言中各类字符串通接函数的代码、混用 strsafe 系列中各类字符串通接函数的代码和混用 Ex 版本 strsafe 系列中各类字符串通接函数的代码。它们各自独立运行一百万次(没错,就是 10,000,000 次)所耗损的时间别离为:
经典 C 语言 —— 7.3 秒
Strsafe 系列—— 8.3 秒
Strsafe 系列 (Ex 版) —— 11.1 秒
在测试中,挪用 Ex 版本的 strsafe 系列函数的措施会在挪用失败时把缓冲区设为 NULL ,并以 0xFE 作为填充字节,代码如下:
DWORD dwFlags = STRSAFE_NULL_ON_FAILURE | STRSAFE_FILL_BYTE(0xFE);
#p#分页标题#e#
个中配置填充字节的代码耗时较多。事实上,假如这里仅仅把缓冲区配置为 NULL 的话,则回收 Ex 版本的 strsafe 系列函数的代码将会与回收普通的 strsafe 系列函数的代码耗时沟通。
由此可见,以上三种方案的机能差别极小。我相信你也不会常常在一个措施中数百万次地重复执行包括大量字符串处理惩罚函数的代码吧!
尚有一点值得引起留意:当你引用 strsafe 系列函数时,原有的 C 语言字符串处理惩罚函数都将被自动举办 #undef 处理惩罚。这也没问题,因为调试进程中的堕落信息将会汇报你哪些函数已经被相应的 strsafe 系列函数代替了。好了,请安心地利用 strsafe.h 吧!更多相关信息请参阅 《Using the Strsafe.h Functions》(http://msdn.microsoft.com/en-us/library/ms647466.aspx)。