当我使用GCC编译使用gets()
函数的C代码时,会收到以下警告:
(.text+0x34): 警告:`gets'函数是危险的,不应该使用。
我记得这与堆栈保护和安全有关,但我不确定具体原因。
如何消除此警告?为什么使用gets()
会产生这样的警告?
如果gets()
如此危险,为什么我们不能将其删除?
当我使用GCC编译使用gets()
函数的C代码时,会收到以下警告:
(.text+0x34): 警告:`gets'函数是危险的,不应该使用。
我记得这与堆栈保护和安全有关,但我不确定具体原因。
如何消除此警告?为什么使用gets()
会产生这样的警告?
如果gets()
如此危险,为什么我们不能将其删除?
gets
的C库维护者发出诚挚邀请:请将您的实现替换为等效的实现。char *gets(char *str)
{
strcpy(str, "Never use gets!");
return str;
}
fgets()
?那个函数是安全的,不像 gets()
。 - FFmpegEnthusiast额外信息:
来自Linux Ubuntu的man 3 gets
,你会看到以下内容(重点标记):
DESCRIPTION Never use this function.
从cppreference.com的wiki页面(https://en.cppreference.com/w/c/io/gets)中可以看到:注意:永远不要使用gets()函数。
注意事项
gets()
函数不执行边界检查,因此该函数极易受到缓冲区溢出攻击。它不能安全地使用(除非程序在限制stdin
上出现什么的环境中运行)。因此,该函数已被弃用,包括第三个C99标准的勘误表中,而在C11标准中完全删除了。fgets()
和gets_s()
是推荐的替代品。永远不要使用
gets()
。
如您所见,该函数已被弃用,并在C11或更高版本中完全删除。
这是我的fgets()
演示用法,带有完整的错误检查:
来自read_stdin_fgets_basic_input_from_user.c:
#include <errno.h> // `errno`
#include <stdio.h> // `printf()`, `fgets()`
#include <stdlib.h> // `exit()`
#include <string.h> // `strerror()`
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
char buf[10];
// NEVER USE `gets()`! USE `fgets()` BELOW INSTEAD!
// USE THIS!: `fgets()`: "file get string", which reads until either EOF is
// reached, OR a newline (`\n`) is found, keeping the newline char in
// `buf`.
// For `feof()` and `ferror()`, see:
// 1. https://en.cppreference.com/w/c/io/feof
// 1. https://en.cppreference.com/w/c/io/ferror
printf("Enter up to %zu chars: ", sizeof(buf) - 1); // - 1 to save room
// for null terminator
char* retval = fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
{
// Check for `EOF`, which means "End of File was reached".
// - This doesn't really make sense on `stdin` I think, but it is a good
// check to have when reading from a regular file with `fgets
// ()`. Keep it here regardless, just in case.
printf("EOF (End of File) reached.\n");
}
if (ferror(stdin))
{
printf("Error indicator set. IO error when reading from file "
"`stdin`.\n");
}
if (retval == NULL)
{
printf("ERROR in %s(): fgets() failed; errno = %i: %s\n",
__func__, errno, strerror(errno));
exit(EXIT_FAILURE);
}
size_t num_chars_written = strlen(buf) + 1; // + 1 for null terminator
if (num_chars_written >= sizeof(buf))
{
printf("Warning: user input may have been truncated! All %zu chars "
"were written into buffer.\n", num_chars_written);
}
printf("You entered \"%s\".\n", buf);
return 0;
}
样本运行及输出:
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=c17 read_stdin_fgets_basic_input_from_user.c -o bin/a && bin/a
Enter up to 9 chars: hello world!
Warning: user input may have been truncated! All 10 chars were written into buffer.
You entered "hello wor".
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=c17 read_stdin_fgets_basic_input_from_user.c -o bin/a && bin/a
Enter up to 9 chars: hey
You entered "hey
".
gets()
可能会存在危险,因为用户可能输入的内容比变量所能存储的空间还要大。第一个回答提到了 fgets()
以及它为什么更加安全。
gets()
缓冲区溢出攻击gets()
函数是一种不安全的输入方法,因为它无法检测用户输入的大小。攻击者可以利用这个漏洞来向程序中的缓冲区写入超出其分配大小的数据,导致缓冲区溢出攻击。攻击者可以利用这种漏洞执行恶意代码或者修改程序的逻辑。为了避免这种攻击,建议使用更加安全的输入方法,如fgets()
。 - EsmaeelEgets()
- EsmaeelEscanf("%s", b)
存在与gets
相同的问题。 - William Pursellgets()
! - Andrew