Is snprintf or vsnprintf better, and how can I ensure I'm using them securely?
我决定在一些旧代码上运行静态分析工具,并且发现了很多使用sprintf的地方。 该工具建议使用vsnprintf或snprintf替换调用,因为sprintf不会对缓冲区溢出进行任何形式的边界检查。
我可以轻松地对调用进行查找和替换,以使其改为使用snprintf或vsnprintf,但我想确保为了确保功能的安全性,无需执行其他任何操作
在某些情况下,所使用的字符串源自用户输入,而在某些情况下则不是。
有人对正确的做法有任何建议吗?
-
"是snprintf还是vsnprintf更好",这取决于您是否具有可变参数或va_list。
-
不担心便携性,不。
-
应该注意的是,C11引入了(甚至)更安全的sprintf_s,snprintf_s,vsnprintf_s。 但是,它们是可选的。
I can easily just do a find and replace on the calls so that it uses snprintf or vsnprintf instead
不,这不是那么容易。 只需查看snprintf或vsnprintf的定义,您就会发现它们采用了名为size的额外参数,用于指定输出缓冲区的长度。 这就是函数名称中的n的含义。 为了使代码安全,您必须查看正在执行sprintf的每个位置,找出可以安全写入输出缓冲区的最大字节数,并将该数字作为size参数传递给或vsnprintf。
不安全的代码:
1 2
| char buffer [10];
sprintf(buffer ,"%d %d", x , y ); // UNSAFE if x and y can be large |
等效安全代码:
1 2
| char buffer [10];
snprintf(buffer , sizeof(buffer ),"%d %d", x , y ); |
也许如果您所有的代码都适合上面的示例,那么您可以搜索并替换。 但是对于更复杂的情况,您可能必须考虑一下。
-
当buffer是指针而不是数组时,搜索替换将无法正确执行操作,但是除非您使用小于指针大小(通常为4或8字节)的缓冲区,否则这只会导致 输出会被过度截断而不是允许溢出。 希望这样的截断错误会在您运行测试后立即显现出来。