sscanf被认为是安全的吗?

我对sscanf很糟糕的建议有一些模糊的记忆。 我知道如果我使用字段宽度说明符,它不会溢出缓冲区,所以我的记忆只是在玩弄技巧吗?

我认为这取决于你如何使用它:如果你正在扫描像int这样的东西,那很好。 如果你正在扫描一个字符串,它不是(除非有一个我忘记的宽度字段?)。


编辑

扫描字符串并不总是安全的。

如果您的缓冲区大小是常量,那么您当然可以将其指定为%20s 。 但如果它不是常量,则需要在格式字符串中指定它,并且您需要执行以下操作:

 char format[80]; //Make sure this is big enough... kinda painful sprintf(format, "%%%ds", cchBuffer - 1); //Don't miss the percent signs and - 1! sscanf(format, input); //Good luck 

这是可能但容易出错,就像我在之前的编辑中所做的那样(忘了处理空终止符)。 您甚至可能溢出格式字符串缓冲区。

sscanf可能被认为是错误的原因是因为它不要求您为字符串参数指定最大字符串宽度,如果从源字符串读取的输入更长,则可能导致溢出。 所以准确的答案是:如果你在格式字符串中正确指定宽度是安全的,否则不是。

请注意,只要缓冲区的长度至少与strlen(input_string)+1一样长, %s%[说明符]就无法溢出。 如果要强制执行更严格的限制,也可以在说明符中使用字段宽度,或者可以使用%*s%*[来抑制赋值,而是使用%n之前和之后获取原始字符串中的偏移量,然后使用它们从输入字符串就地读取结果子字符串。

是的,如果你指定字符串宽度,那么没有与缓冲区溢出相关的问题。

无论如何,就像@Mehrdad向我们展示的那样,如果在编译时没有建立缓冲区大小,则可能会出现问题。 我想限制可以提供给sscanf的字符串的长度,可以消除问题。

有2点需要注意。

输出缓冲区[s]。

如其他人所提到的,如果你指定一个小于或等于格式字符串中输出缓冲区大小的大小,那么你是安全的。

输入缓冲区。

在这里,您需要确保它是一个空终止字符串,或者您不会读取超过输入缓冲区大小。

如果输入字符串不是空终止,则sscanf可能会读取超出缓冲区的边界并在未分配存储器时崩溃。

所有scanf函数都有基本的设计缺陷,其中只有一些可以修复。 它们不应该用在生产代码中。

  • 如果一个值超出你存储值的变量的可表示范围,则数字转换具有全面的恶魔 – 飞出你的未定义行为。 我没有这样做 。 允许C库崩溃您的程序只是因为有人输入了太多的输入数字。 即使它没有崩溃,它也没有义务做任何明智的事情。 没有解决方法。

  • 正如其他几个答案所指出的, %s和臭名昭着的一样危险。 通过使用’m’修饰符或字段宽度可以避免这种情况,但您必须记住为要转换的每个文本字段执行此操作,并且必须将字段宽度连接到格式字符串 – – 你不能将sizeof(buff)作为参数传递。

  • 如果输入与格式字符串不完全匹配,则sscanf不会告诉您在放弃之前输入缓冲区中有多少字符 。 这意味着唯一可行的错误恢复策略是丢弃整个输入缓冲区。 如果您正在处理某种类型的简单线性数组记录(例如,使用CSV文件,“跳过格式错误的行并继续下一个”,这是一个合理的错误恢复策略),这可能没问题,但是如果你输入的结构不止于此,你就是软管。

在C中,解析作业不够复杂,无法certificate使用lexyacc通常最好使用POSIX regexps( regex.h )或手动字符串解析。 strto*数值转换函数在溢出时确实具有明确且有用的行为,并告诉您它们如何使用输入的字符,而string.h为手动解析器( strchrstrcspnstrsep等)提供了许多方便的函数。 )。