如果有人抱怨gets(),为什么不对scanf(“";%s";,…”)也这样做呢?
从如果有人抱怨gets(),为什么不对scanf(“";%s";,…”)也这样做呢?,c,scanf,buffer-overflow,gets,buffer-overrun,C,Scanf,Buffer Overflow,Gets,Buffer Overrun,从中,人得到了: 永远不要使用get()。因为它是 不知道真相就说不出来 数据提前多少 将读取字符get(),然后 因为gets()将继续存储 超过缓冲区结尾的字符, 使用它是极其危险的。 它被用来破坏计算机 安全改用fgets() 几乎所有我看到的scanf的使用方式都应该有相同的问题():scanf(“%s”,string)。这个问题在这种情况下存在吗?为什么scanf手册页中没有关于它的参考资料?为什么gcc在使用-Wall编译时不发出警告 ps:我知道有一种方法可以用scanf在格式字符
中,人得到了:
永远不要使用get()。因为它是
不知道真相就说不出来
数据提前多少
将读取字符get(),然后
因为gets()将继续存储
超过缓冲区结尾的字符,
使用它是极其危险的。
它被用来破坏计算机
安全改用fgets()
几乎所有我看到的scanf
的使用方式都应该有相同的问题():scanf(“%s”,string)
。这个问题在这种情况下存在吗?为什么scanf
手册页中没有关于它的参考资料?为什么gcc在使用-Wall
编译时不发出警告
ps:我知道有一种方法可以用scanf
在格式字符串中指定字符串的最大长度:
char str[10];
scanf("%9s",str);
编辑:我不是在问我前面的代码是否正确。我的问题是:如果scanf(“%s”,string)
总是错误的,为什么没有警告,手册页中也没有警告?使用get()
永远都不安全scanf()
可以安全使用,正如您在问题中所说。但是,确定您是否安全地使用它对于编译器来说是一个更难解决的问题(例如,如果您在一个函数中调用scanf()
,其中您将缓冲区和字符计数作为参数传递,它将无法判断);在这种情况下,它必须假设您知道自己在做什么。可能只是scanf将根据读取的数据量在堆上分配空间。由于它不会分配缓冲区,然后在读取空字符之前进行读取,因此不会有覆盖缓冲区的风险。相反,它读入自己的缓冲区,直到找到空字符,并在读取结束时将该缓冲区复制到另一个大小正确的缓冲区。当编译器查看scanf
的格式化字符串时,它会看到一个字符串!这是假设在运行时未输入格式化字符串。一些编译器(如GCC)具有一些额外的功能来分析在编译时输入的格式化字符串。这种额外的功能并不全面,因为在某些情况下需要运行时开销,这对于C语言来说是不可能的。例如,在这种情况下,您是否可以在不插入额外隐藏代码的情况下检测到不安全的使用:
char* str;
size_t size;
scanf("%z", &size);
str = malloc(size);
scanf("%9s"); // how can the compiler determine if this is a safe call?!
当然,如果指定要读取的字符数,并且有足够的内存来保存字符串,则可以使用scanf
编写安全代码。在获取
的情况下,无法指定要读取的字符数。我不确定为什么scanf的手册页没有提到缓冲区溢出的可能性,但vanilla scanf不是一个安全选项。一个相当过时的链接显示了这一点。此外,请检查此项(不是gcc,但信息丰富)答案很简单,没有人在gcc中编写代码来生成该警告
正如您所指出的,针对“%s”
(没有字段宽度)的特定情况的警告非常合适
但是,请记住,这仅适用于scanf()
、vscanf()
、fscanf()
和vfscanf()
的情况。使用sscanf()
和vsscanf()
时,此格式说明符可以非常安全,因此在这种情况下不应发出警告。这意味着您不能简单地将其添加到现有的“scanf样式格式字符串”分析代码中;您必须将其拆分为“fscanf样式格式字符串”和“sscanf样式格式字符串”选项
我敢肯定,如果你为最新版本的GCC制作补丁,它很有可能被接受(当然,你也需要为glibc头文件提交补丁)。你的维基百科链接说scanf
不安全。@aviraldg你说得对,我以前读过,但我没有找到一个好的方法来写标题。我编辑了它。每个人都回答:scanf(“%s”,…)
不安全。关于此的另一个参考:。我仍然不明白为什么手册页上没有这方面的内容;scanf不在堆上分配空间。提供缓冲区是程序员的工作。dbarbosa所说的Scanf是不安全的。请看本教程,它更详细、更准确地解释了我刚才所说的内容scanf
不分配自己的存储。您链接的a
标志是GNU扩展,而不是C标准的一部分。您链接到的教程中说,scanf()分配自己内存的标志是GNU特定的扩展。在标准C中,scanf()不分配存储。应该注意的是,不仅此GNU扩展在很大程度上是无用的(因为您的代码将是不可移植的,并且在缺少“a”功能的系统上,无法在应用程序级别向scanf
添加“a”功能),但它直接与C99功能冲突-%a
表示十六进制浮点,如在printf
中,它是另一个用于读取带有scanf
的浮点的说明符。是的,您是对的,但gcc会在参数的数量或类型不正确时警告您。在这些情况下,它不会假定您知道自己在做什么。@dbarbosa:所有信息都可供编译器检查可选参数的数量是否与格式字符串中的格式说明符的数量相同。同样,它也有足够的信息来检查格式字符串(例如)中是否有%d
,相应的参数是否为整数。它无法知道指定的大小是否正确,但如果没有任何大小规范,它可以知道它只是错了scanf(“%5s”,string)
根据string
的大小可以是对的,也可以是错的,但它不能像您所说的那样说。然而