登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 程序员学前班[不再更新,只读] >> 主题: 我怎样才知道对于任意的 sprintf 调用需要多大的目标缓冲区?[zt]     [回主站]     [分站链接]
标题
我怎样才知道对于任意的 sprintf 调用需要多大的目标缓冲区?[zt]
我是马甲
浏览(0) + 2007-06-05 17:30:21 发表 编辑

关键字:

13.19 我怎样才知道对于任意的 sprintf 调用需要多大的目标缓冲区? 怎样才能避免 sprintf() 目标缓冲区溢出?
当用于 sprintf() 的格式串已知且相对简单时, 你有时可以预测出缓冲区的大小。 如果格式串中包含一个或两个 %s, 你可以数出固定字符的个数再加上对插入的 字符串的 strlen() 调用的返回值。对于整形, %d 输出的字符数不会超过
((sizeof(int) * CHAR_BIT + 2) / 3 + 1) /* +1 for '-' */
CHAR_BIT 在 中定义, 但是这个计算可能 有些过于保守了。它计算的是数字以八进制存储需要的字节数; 十进制的存储可 以保证使用同样或更少的字节数。

当格式串更复杂或者在运行前未知的时候, 预测缓冲区大小会变得跟重新实现 sprintf 一样困难, 而且会很容易出错。有一种最后防线的技术, 就是 fprintf() 向一块内存区或临时文件输出同样的内容, 然后检查 fprintf 的返回值或临时文件 的大小, 但请参见问题 19.14, 并提防写文件错误。

如果不能确保缓冲区足够大, 你就不能调用 sprintf(), 以防缓冲区溢出后改写 其它的内存区。如果格式串已知, 你可以用 %.Ns 控制 %s 扩展的长度, 或者使用 %.*s, 参见问题 12.9。

要避免溢出问题, 你可以使用限制长度的 sprintf() 版本, 即 snprintf()。 这样使用:
snprintf(buf, bufsize, "You typed \"%s\"", answer);
snprintf() 在几个 stdio 库中已经提供好几年了, 包括 GNU 和 4.4bsd。 在 C99 中已经被标准化了。

作为一个额外的好处, C99 的 snprintf() 提供了预测任意 sprintf() 调用所需的 缓冲区大小的方法。C99 的 snprintf() 返回它可能放到缓冲区的字符数, 而它又 可以用 0 作为缓冲区大小进行调用。因此
nch = snprintf(NULL, 0, fmtstring, /* 其它参数 */ );
这样的调用就可以预测出格式串扩展后所需要的字符数。

另一个 (非标准的) 选择是 asprintf() 函数, 在 bsd 和 GNU 的 C 库中都有提供, 它调用 malloc 为格式串分配空间, 并返回分配内存区的指针。这样使用:
char *buf;
asprintf(&buf, "%d = %s", 42, "forty-two");
/* 现在, buf 指向含有格式串的 malloc 的内存 */

参考资料: [C9X, Sec. 7.13.6.6]。

来自 http://c-faq-chn.sourceforge.net/ccfaq/node210.html

我是马甲
2007-6-5 17:35:25 发表 编辑

vc6中似乎没有这个函数,要用 _snprintf
我是马甲
2007-6-5 17:37:04 发表 编辑

众所周知,sprintf不能检查目标字符串的长度,可能造成众多安全问题,所以都会推荐使用snprintf.

snprintf(_snprintf)的声明是这样的

int _snprintf(
char *buffer,
size_t count,
const char *format [,
argument] ...
);


If len < count, then len characters are stored in buffer, a null-terminator is appended, and len is returned.

If len = count, then len characters are stored in buffer, no null-terminator is appended, and len is returned.

If len > count, then count characters are stored in buffer, no null-terminator is appended, and a negative value is returned.


最常见的错误用法有:
1.
char sa[256]={0};
_snprintf(sa,sizeof(sa),"%s",sb);
//错误原因:当sb的长度>=256的时候,sa将没有'\0'结尾

2.
char sa[256];
_snprintf(sa,sizeof(sa)-1,"%s",sb);
//错误原因:当sb的长度>=255的时候,sa将没有'\0'结尾,忘记给sa初始化

3.
char sa[256];
_snprintf(sa,sizeof(sa)-1,"%s",sb);
sa[sizeof(sa)]=0;
//错误原因:最后一行数组越界

正确的用法
1. //推荐用法
char sa[256];
sa[sizeof(sa)-1]=0;
_snprintf(sa,sizeof(sa),"%s",sb);
if(sa[sizeof(sa)-1]!=0)
{
printf("warning:string will be truncated");
sa[sizeof(sa)-1]=0;
}

2.
char sa[256]={0};
int result = _snprintf(sa,sizeof(sa),"%s",sb);
if(result==sizeof(sa) || result<0)
{
printf("warning:sting will be truncated");
sa[sizeof(sa)-1]=0;
}
Feedback
# re: 谈谈snprintf 回复 更多评论
2006-09-30 16:48 by 阿福
朋友,我觉得我的方法更简单,更好:
char sa[256];
_snprintf(sa, sizeof(sa), "%s\0", sb);
//在格式化的时候要求在最后加一个0就行了嘛!
# re: 谈谈snprintf 回复 更多评论
2006-09-30 18:15 by 小明
TO 阿福:
你这样是不行的。简化一下说明一下
char sa[2];
char sb[3]="aa";
_snprintf(sa, sizeof(sa), "%s\0", sb);

==> sa="aa",但是没有'\0'结束
# re: 谈谈snprintf 回复 更多评论
2006-10-18 17:36 by Sim
TO 小明

你们用的都是什么系统啊
在linux下从来都是
char sa[2];
char sb[3]="aa";
snprintf(sa, sizeof(sa), "%s", sb);
这样用的, 而且sa=>"a", 系统会自动阶段
# re: 谈谈snprintf 回复 更多评论
2007-06-03 01:19 by yecheng_110
linux和windows下是不同的
linux下的snprintf没有这个问题
而windows下的_snprintf才有这个问题


总数:2 页次:1/1 首页 尾页  
总数:2 页次:1/1 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1