文档章节

Strsafe.h:更安全的C语言字符串处理函数

rise-worlds
 rise-worlds
发布于 2016/06/20 13:36
字数 1439
阅读 1
收藏 0

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

作者:Michael Howard
原文出处:Strsafe.h: Safer String Handling in C

  在微软公司举行的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》
这些新函数包含在一个头文件和一个函数库(可选)中,而后两者能在新版的 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);
}

  以上代码中的 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);

  其中设置填充字节的代码耗时较多。事实上,如果这里仅仅把缓冲区设置为 NULL 的话,则采用 Ex 版本的 strsafe 系列函数的代码将会与采用普通的 strsafe 系列函数的代码耗时相同。
  由此可见,以上三种方案的性能差异极小。我相信你也不会经常在一个程序中数百万次地反复执行包含大量字符串处理函数的代码吧!
还有一点值得引起注意:当你引用 strsafe 系列函数时,原有的 C 语言字符串处理函数都将被自动进行 #undef 处理。这也没问题,因为调试过程中的出错信息将会告诉你哪些函数已经被相应的 strsafe 系列函数取代了。好了,请放心地使用 strsafe.h 吧!更多相关信息请参阅 《Using the Strsafe.h Functions》

本文转载自:http://www.cnblogs.com/flying_bat/archive/2009/03/20/1417463.html

rise-worlds

rise-worlds

粉丝 3
博文 1760
码字总数 1380
作品 0
深圳
程序员
私信 提问
《windows核心编程系列》谈谈ANSI和Unicode字符集

2012、8、28 第二章:字符和字符串处理 使用vc编程时项目--》属性--》常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集。一般情况下说Unicode都是指...

长平狐
2012/10/08
722
0
在Swift中使用C语言的指针

Objective-C和C语言经常需要使用到指针。Swift中的数据类型由于良好的设计,使其可以和基于指针的C语言API无缝混用。同时Swift也可以自动处理大多数将指针作为参数的情况。在这篇文章里,我们...

DevTalking
09/29
0
0
Redis字符串类型实现内幕

摘要 Redis不仅仅是一个key-value存储,它更是一个数据结构服务,支持不同类型的值。这意味着在传统的key-value存储中,我们用string的key关联string的value。而在Redis中,我们可以存储的值...

Float_Luuu
2016/05/15
1K
0
Go语言学习笔记 package

加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 strings strings包实现了用于操作字符的简单函数。 strings.Index("suoning", "n") //3(子串第一次出现的位置,不存在则返回...

xumaojun
2018/03/12
0
0
Redis设计与实现系列-基本数据结构-SDC

关于《Redis设计与实现》读书笔记 SDC全称是(simple dynamic string,SDS),Redis是以C语言编写的,但是Redis并没有直接使用C语言内置的字符串(C语言内置的字符串以空格结束),Redis自己构...

申文波
2018/07/30
92
0

没有更多内容

加载失败,请刷新页面

加载更多

mars-config 动态配置管理

mars-config 码云地址:https://gitee.com/fashionbrot/mars-config 介绍 spring mvc 、springboot 动态配置系统。http 轮训方式 更新 动态配置 软件架构 软件架构说明 后端使用技术 :sprin...

fashionbrot
16分钟前
9
0
女朋友玩吃鸡手游被开挂老哥骗炮,我见义勇为将骗子绳之以法

大家好,我是乔哥。 晚上10点以后下班后我回到自如出租房里面,开始处理公众号粉丝发来的消息,一条一条处理,突然看到了这么几条消息,吸引了我的眼球: 然后我就和这位女粉丝小红(化名)聊...

gzc426
21分钟前
3
0
两款软件

fadetop保护眼睛软件 Snipaste截图软件

伟大源于勇敢的开始
48分钟前
6
0
06.全局锁和表锁

根据加锁的范围,MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类。 全局锁 全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是flush tables with read lock(FTW...

scgaopan
今天
7
0
图解安装CentOS8

最近正式发布了CentOS8!迫不及待地准备下载了CentOS8镜像,准备体验下,工作繁忙无暇理会。 今天抽空安装体验下~ 可从CentOS官网下载:https://centos.org/download/ 为了快速可以选择从国...

技术训练营
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部