我又需要帮助!我认为使用该gets()函数非常酷,因为它就像scanf()我可以获得带有空格的输入.但我在其中一个线程(学生信息文件处理)中读到它不好用,因为根据它们,它是一个用于创建缓冲区溢出的魔鬼工具(我不明白)
如果我使用该gets()功能,我可以这样做.输入你的名字:Keanu Reeves.
如果我使用scanf(),我只能这样做.输入你的名字:Keanu
所以我听取了他们的建议并用我的gets()代码替换了fgets().问题是现在我的一些代码不工作了...有没有比其他任何功能gets()及fgets()能读整条生产线和忽略空格.
cas*_*nca 40
它是用于创建缓冲区溢出的魔鬼工具
因为gets不接受长度参数,所以它不知道输入缓冲区有多大.如果你传入一个10个字符的缓冲区并且用户输入100个字符 - 那么,你就明白了.
fgets是一种更安全的替代方法,gets因为它将缓冲区长度作为参数,因此您可以像这样调用它:
fgets(str, 10, stdin);
Run Code Online (Sandbox Code Playgroud)
它最多可读取9个字符.
问题是现在我的一些代码不再起作用了
这可能是因为fgets还将最终的换行符(\n)存储在缓冲区中 - 如果您的代码不期望这样,您应该手动删除它:
int len = strlen(str);
if (len > 0 && str[len-1] == '\n')
str[len-1] = '\0';
Run Code Online (Sandbox Code Playgroud)
Dar*_*rel 14
正如其他响应所指出的那样,gets()不检查缓冲区空间.除了意外溢出问题之外,恶意用户还可以利用这种弱点来制造各种各样的破坏.
1988年发布的第一批广泛传播的蠕虫之一曾经gets()在整个互联网上传播.以下是Peter Van Der Linden 撰写的Expert C Programming的有趣摘录,其中讨论了它的工作原理:
早期的Bug得到了()Internet蠕虫
C中的问题并不仅限于语言.标准库中的一些例程具有不安全的语义.1988年11月,蠕虫程序在互联网网络上蠕动了数千台机器,这大大证明了这一点.当烟雾消失并且调查完成后,确定蠕虫传播的一种方式是通过finger守护程序中的弱点,该守护程序通过网络接受有关当前登录的人的查询.finger守护程序in.fingerd使用标准I/O例程gets().
标称任务gets()是从流中读取字符串.调用者告诉它将传入的字符放在哪里.但是gets()不检查缓冲区空间; 实际上,它无法检查缓冲区空间.如果调用者提供了一个指向堆栈的指针,并且输入的数量多于缓冲区空间,gets()则会很乐意覆盖堆栈.该finger守护程序包含的代码:
main(argc, argv)
char *argv[];
{
char line[512];
...
gets(line);
Run Code Online (Sandbox Code Playgroud)
这line是一个在堆栈上自动分配的512字节数组.当用户提供比finger守护进程更多的输入时,gets()例程将继续将其放在堆栈上.大多数体系结构都容易被覆盖堆栈中间的现有条目覆盖更大的东西,这也会覆盖相邻的条目.在软件中检查每个堆栈访问的大小和权限的成本是高昂的.知识渊博的犯罪分子可以通过在参数字符串中存储正确的二进制模式来修改堆栈中过程激活记录中的返回地址.这会将执行流程转移回原来的位置,而是转移到一个特殊的指令序列(也小心地存放在堆栈中)execv()用shell替换正在运行的图像.Voilà,您现在正在与远程计算机上的shell而不是finger守护程序进行通信,您可以发出命令将病毒副本拖到另一台计算机上.
具有讽刺意味的是,该gets()例程是一个过时的功能,它提供了与第一版便携式I/O库的兼容性,并在十多年前被标准I/O取代.该联机帮助页甚至强烈建议fgets()始终使用.在fgets()常规设置的字符阅读次数的限制,所以它不会超过缓冲区的大小.该finger守护程序通过替换的两行修复程序变得安全:
gets(line);
Run Code Online (Sandbox Code Playgroud)
按行:
if (fgets(line, sizeof(line), stdin) == NULL)
exit(1);
Run Code Online (Sandbox Code Playgroud)
这吞下了有限数量的输入,因此不能被操作该程序的人操纵覆盖重要位置.但是,ANSI C标准没有gets()从语言中删除.因此,虽然这个特定的程序是安全的,但C标准库中的潜在缺陷并未被删除.