snprintf和相关函数是否安全使用?

4

最近在stackoverflow(为什么有人会使用strncpy而不是strcpy?)上有一个问题,其中有回答(回答1回答2),让我对其他带有“n”的字符串函数感到不确定,例如snprintf(我一直在广泛使用)。 snprintf是否安全?总的来说,“n”系列中的哪些函数是安全的?


1
相关提示:要小心在不同平台上,snprintf/swprintf/snwprintf等函数以及%ls和%s格式化输出所产生的不同行为。它们之间有很大差异。 - Jared Oberhaus
1
只有在损坏的、不符合规范的实现中才会出现这种情况。C标准非常清楚这些格式说明符应该做什么。 - R.. GitHub STOP HELPING ICE
5个回答

15

strncpy()是一个奇怪的函数,它的命名不太准确 - 它的原始目的是确保一个缓冲区完全被初始化为一个字符串的内容(而不会溢出目标),并将缓冲区的其余部分用零填充。据我所知,最初的目的是处理文件系统目录条目 - 目标缓冲区在某种意义上并不像C库中的其他strxxx()函数一样是一个字符串。 strncpy()的主要问题是,如果源字符串大于目标缓冲区,则结果将不会以空字符结尾。

大多数其他处理字符串的“n”函数都会正确终止字符串,但也有例外,例如微软的扭曲版本_snprintf()。正确的C99snprintf()会始终将目标字符串以空字符结尾(只要目标缓冲区的大小大于0)。

有一个名为TR 24731的技术报告,提出了一组边界检查替代方案,用于处理字符串和内存缓冲区的函数。 TR的目标之一是使函数的参数、结果和错误行为在函数之间更加相似。 TR似乎具有一定的接受度,但我认为它除了Microsoft的编译器之外并没有得到广泛实现(我认为微软是TR的主要推动者)。您可以在此处获取更多信息:

即使您不是这些提议的粉丝,我认为它们对于了解现有函数存在的问题非常有教育意义。


1
顺便提一下,微软的实现是不符合标准的。https://dev59.com/73RC5IYBdhLWcg3wOOP1 - Deduplicator

1

snprintf虽然不会在给出正确参数的情况下溢出缓冲区,但请记住它与*printf家族的其他成员共享所有格式字符串漏洞。例如,%n说明符很危险,因为攻击者可以使用它将任意字节写入任意内存位置。请参见CERT C编码标准维基上的FIO30-C. Exclude user input from format strings


0
只要为缓冲区提供正确的长度,就可以保证安全。

你提供的长度(以及是否手动将缓冲区的末尾置空)取决于你所在的平台。 - Jared Oberhaus

-2

1
实际上,snprintf根本不保证缓冲区溢出。这取决于您提供的缓冲区大小,可能是不正确的。 - akif
不用说,没有 CRT 函数可以神奇地知道传入的缓冲区实际有多大。 - Drew Hoskins
2
那么,毫无疑问,没有任何 CRT 函数是“安全的”,人们绕着这个规则假装在它们所有名称后添加 _s 没有太多意义。;-) - Steve Jessop
6
你应该澄清你所说的是有问题的 Microsoft 实现而不是 C 标准。 - R.. GitHub STOP HELPING ICE
C标准的snprintf确保在缓冲区末尾写入\0,并且不会发生缓冲区溢出。当然,这取决于您传递的大小参数,但您可以对snprintf_s执行完全相同的操作,并且由于相同的原因而失败。 - undefined

-4

注意:不同的平台在传递给 snprintf 的字符串的空终止行为方面有不同的行为。


7
ISO C99 中规定的 snprintf 函数保证以空字符结尾。 - Pavel Minaev
1
这就是ISO C99的规定:然而,在某些平台上的行为是不同的。你需要进行实验和验证每个平台以确保。 - Jared Oberhaus
3
请问您能否举例说明一个在这方面不符合标准C的平台? - Martin v. Löwis
3
Microsoft的变体函数_snprintf()如果缓冲区不够大,就不会终止目标字符串:http://msdn.microsoft.com/en-us/library/2ts7cx93.aspx。 - Michael Burr
6
有一个函数名以下划线开头的非标准函数存在不符合规范的问题,为什么不直接用标准函数名称包装它,并同时修复缺乏终止的错误呢? - R.. GitHub STOP HELPING ICE
2
如果可以的话,我会投票反对这个。它绝对是错误的。如果你选择使用非标准的、命名不同的_snprintf,那么它的行为可能会有所不同。然而,这不是提交者所问的。看起来在Windows上snprintf是不可用的;但是,你可以很容易地自己编写一个。 - cmccabe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接