`scanf("%d", ...)` 和 `gets` 一样糟糕吗?

Wil*_*ell 5 c scanf

多年来,gets它一直被普遍贬低为不安全的功能。(典型的问题是为什么 gets 函数如此危险以至于不应该使用它?)。该gets函数太糟糕了,以至于它已从 C11 语言标准中删除。支持者gets(如果有的话,也很少)会争辩说,如果您了解输入的结构,那么使用它是完全可以的。

为什么那些贬低gets并承认依赖输入结构的愚蠢的人允许使用%d用作scanf转换说明符?这是一个社会学问题,真正的问题是:为什么%d格式scanf字符串不安全?

Wil*_*ell 5

如果格式字符串scanf包含原始%d转换说明符(“raw”表示“没有最大字段宽度”),并且输入流包含的字符串是无法放入int. 例如,字符串不能在平台 where 中5294967296表示。该语言仅保证 an足够大以容纳 -32767 到 +32767 的范围,因此包含该字符串的任何输入流都可能导致未定义的行为。这种潜在的未定义行为可以通过使用来避免。大多数现代平台的 INT_MAX 值远大于 32767,因此实际上转换说明符上的宽度修饰符可以大于 4,但应该根据平台确定(在编译时或运行时) ,并且它必须出现在格式字符串中。intsizeof(int) == 4Cint32768%4d

如果您不添加宽度修饰符,您也可以只使用将gets一行读入缓冲区并用于sscanf解析值。这(也许)会使错误对读者来说更加明显。

  • 我承认你所描述的问题。我否认在实践中它与使用“gets()”一样有问题。 (12认同)
  • 我觉得这个答案是在恳求超级猫加入关于 C 实现的评论,而不是在 UB 发生时随意选择做无意义的事情。 (6认同)
  • 或者像没有宽度的“%s”一样糟糕。 (5认同)

Ste*_*mit 4

不,scanf("%d", \xe2\x80\xa6)没有那么糟糕gets

\n

gets之所以如此糟糕,是因为几乎不可能在任何环境中安全地使用它。缓冲区溢出是有可能发生的,无法避免,并且很可能导致任意严重的后果。

\n

scanf("%d", \xe2\x80\xa6)另一方面,可能发生的最糟糕的事情是整数溢出。虽然这在理论上也是未定义的行为,但实际上它总是会导致(a)安静的环绕,(b)溢出到INT_MAXINT_MIN,或 (c) 可能终止调用程序的运行时异常。

\n

很难想象攻击者可以利用使用scanf("%d", \xe2\x80\xa6). 涉及的漏洞gets另一方面,

\n

(虽然不是问的问题,但这确实scanf("%s", \xe2\x80\xa6)gets。这是一个公平的问题,为什么前者并不总是像后者一样受到强烈贬低。)

\n