曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6547|回复: 0
打印 上一主题 下一主题

使用通用类型 _stprintf_s() 与 sizeof 时发生的溢出

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-9-11 11:13:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
首先知道一点,sizeof 用来计算数组时,是计算数组字节的,而不是数组的元素个数。这一点,在使用 sizeof 来计算通常的 char 类型数组时,所得到的值既表示数组的元素个数又表示数组的整个大小。但 sizeof 用来计算 Unicode 或者说是 wchar_t 这类型的数组时要小心,否则很可能造成缓冲区溢出。

比如,如果声明一个数组 TCHAR buffer[256]; 那么用 sizeof 来测量该数组是 512 ,而不是 256,尽管 buffer 数组中的元素为 wchar_t 类型且为 256 个。

_stprintf_s() 函数是 sprintf() 的通用类型,它的第 2 个函数在 MSDN 里表示 "Maximum number of characters to store." ,即要存储的字符数的最大个数。下面的这个程序里,我们可能会不小心如下使用 _stprintf_s() 和 sizeof() :
[C++] 纯文本查看 复制代码
#include "stdafx.h"

int _tmain(int argc, LPTSTR argv[])
{
    TCHAR buf[100];
    int len = _stprintf_s(buf, sizeof(buf), _T("%s"), _T("Hello World"));
    printf("wote %d characters\n", len);
    
    return 0;
}


程序初看上去没什么问题,但是如果是定义了 _UNICODE 后(此时 buf 里的元素类型是 wchar_t 而不是 char) 问题就来了。

上面程序运行后会崩溃,为什么会发生这种情况呢?我们不是只写了一个 "Hello World" 到 buf 中吗?而 buf 的空间又足以容纳这个字符串。此时,你可能会单步去调试,发现程序是在 return 0; 后发生了崩溃 -- 调试器还可能会好心的提示你发生了缓冲区溢出。

实际上,问题的关键在与 _stprintf_s() 中的第 2 个参数 sizeof(buf) ,它的值是 200,而不是 100 --- 这是程序崩溃的关键所在!在 _stprintf_s() 函数里,会有这么一道工序,在将 "Hello World" 填入 buf  之后,_stprintf_s() 还会调用 memset() 来清理一下 "Hello World" 后面的一段空间(这段空间的长度和 "Hello World" 的长度加起来刚好等于 400,即 200 个 wchar_t 类型长度)。如此一来,势必会冲毁 main() 函数的返回地址 --- 所以当程序执行过 return 0; 时因为找不到返回地址而发生崩溃。

因此,当我们使用如 _stprintf_s() 这种通用类型的函数时,要小心第 2 个参数的使用,特别是使用 sizeof() 直接来计算数组长度时!如果确定数组元素为 wchar_t 类型,那么 _stprintf_s() 函数的第 2 个参数应该这么写 sizeof(buf)/2 。一般情况下,最简单且安全的办法是,数组的元素个数用一个宏来表示,则 _stprintf_s() 的第 2 个参数就直接用该宏作为参数。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-3 00:28 , Processed in 0.083360 second(s), 24 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表