c - 替换已弃用的 gets()

标签 c getline buffer-overflow gets

我正在使用 CMU-Cambridge 的 SLM 工具包对语言数据进行一些基线语言建模,但是当我运行其中一个内置的可执行文件时,我的系统在尝试执行其中一个命令时检测到缓冲区溢出。

基于this StackOverflow question我注意到__gets_chk+0x179引起了这个问题,我发现 gets/fgets 出现两次在源代码中(evallm.c,也可用 in this GitHub project someone made ),但我不知道如何以正确/安全的方式修复它们。

错误消息的相关部分:

*** buffer overflow detected ***: /home/CMU-Cam_Toolkit_v2/bin/evallm terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__gets_chk+0x179)[0x7f613bc719e9]
Aborted

broken code

# declaration of input string variable
char input_string[500];

# occurence 1
...
while (fgets (wlist_entry, sizeof (wlist_entry),context_cues_fp)) { ... } 
...

# occurence 2
...
while (!feof(stdin) && !told_to_quit) {
    printf("evallm : ");
    gets(input_string);
....

错误基本上发生在我将 input_string 提供给 evallm 时。命令太长。通常从命令行调用它,您可以交互地传递参数。但是,我将所有参数与命令一起通过管道传输(如文档示例中所示),但显然有时我的参数名称占用了太多字节。当我将 input_string 的数组长度从 500 更改为 2000 时,问题就解决了(所以我猜错误是由于发生 2 引起的)。但我真的想通过替换 gets() 来修复它通过getline()因为这似乎是正确的方法。或者将其替换为 fgets()还有解决办法吗?如果是这样,我应该使用什么参数?

但是,当尝试替换gets()时,我总是遇到编译错误。我不是 C 程序员(Python、Java),也不熟悉 getline() 的语法,所以我正在努力寻找正确的参数。

最佳答案

在您的特定情况下,您知道 input_string 是一个 500 字节的数组。 (当然,您可以将 500 替换为 2048)

我很偏执,擅长防御性编程,我会在任何输入之前将缓冲区清零,例如

memset(input_string, 0, sizeof(input_string));

因此,即使 fgets 失败,缓冲区也会被清除。在大多数情况下,这原则上是没有用的。但也有一些极端情况,而问题就在于细节。

所以请阅读 fgets(3) 的文档并将 gets 调用替换为

fgets(input_string, sizeof(input_string), stdin);

(您实际上应该处理极端情况,例如 fgets 失败以及输入行长于 input_string ....)

当然,您可能希望将终止换行符归零。为此,添加

int input_len = strlen(input_string);
if (input_len>0) input_string[input_len-1] = '\0`;

(如评论所述,您可能会减少清除 input_string 的频率,例如在启动时和 fgets 失败时)

请注意 getline(3)是 POSIX 特定的并且正在管理堆分配的缓冲区。了解 C dynamic memory allocation 。如果您不熟悉 C 编程,这对您来说可能会很棘手。顺便说一句,您甚至可以考虑使用 Linux 特定的 readline(3)

要点是您对 C 编程的熟悉程度。

注意:在 C 语言中,# 并不开始注释,而是开始 preprocessor指令。

关于c - 替换已弃用的 gets(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40656902/

相关文章:

编译 C 以允许缓冲区溢出

c - 缓冲区溢出: execute char array loaded into memory

c++ - 包含 malloc 声明的头文件的名称是什么?

c++ - Ubuntu 中 getline 的段错误

c - 在c中的结构内声明数组

c++ - 为什么我在使用 getline() 时遇到问题? "No instance of overloaded functions matches the argument list"和 "data is ambiguous"

c++ - 如何使用友元运算符存储一串字符?

c - 这段代码容易受到缓冲区溢出的影响吗?

c++ - 为 C++ 编译时找不到符号,但为 C 找到了

c - 分段故障。为什么这个指针指向无效地址?