替换弃用的 gets()
Replace deprecated gets()
我正在使用 CMU-Cambridge 的 SLM 工具包对语言数据进行一些基线语言建模,但是当我 运行 构建的可执行文件之一时,我的系统在尝试执行一个时检测到缓冲区溢出命令的数量。
基于 this Whosebug question I noticed that __gets_chk+0x179
caused the problem, and I've found two occurrences of gets/fgets
in the source code (evallm.c, also available in this GitHub project someone made) 但我不知道如何以 proper/secure 方式修复它们。
错误信息的相关部分:
*** 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);
....
这个错误基本上是在我给evallm
命令的input_string太长的时候出现的。通常它是从命令行调用的,您可以交互式地传递参数。但是,我将所有参数与命令一起通过管道传输(如文档示例中所示),但显然有时我的参数名称占用了太多字节。当我将 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] = '[=12=]`;
(如评论所述,您可能不太经常清除 input_string
,例如在开始时和 fgets
失败时)
注意 getline(3) is POSIX specific and is managing a heap-allocated buffer. Read about C dynamic memory allocation. If you are unfamiliar with C programming, that might be tricky to you. BTW, you could even consider using the Linux specific readline(3)
主要是你对C编程的熟悉程度。
注意:在 C 中,#
不是开始注释,而是 preprocessor 指令。
您将 gets
替换为 fgets
。
几乎就这么简单,区别(除了参数)是 fgets
缓冲区末尾可能有一个换行符。 (请注意,我说 可能 在那里。)
我正在使用 CMU-Cambridge 的 SLM 工具包对语言数据进行一些基线语言建模,但是当我 运行 构建的可执行文件之一时,我的系统在尝试执行一个时检测到缓冲区溢出命令的数量。
基于 this Whosebug question I noticed that __gets_chk+0x179
caused the problem, and I've found two occurrences of gets/fgets
in the source code (evallm.c, also available in this GitHub project someone made) 但我不知道如何以 proper/secure 方式修复它们。
错误信息的相关部分:
*** 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);
....
这个错误基本上是在我给evallm
命令的input_string太长的时候出现的。通常它是从命令行调用的,您可以交互式地传递参数。但是,我将所有参数与命令一起通过管道传输(如文档示例中所示),但显然有时我的参数名称占用了太多字节。当我将 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] = '[=12=]`;
(如评论所述,您可能不太经常清除 input_string
,例如在开始时和 fgets
失败时)
注意 getline(3) is POSIX specific and is managing a heap-allocated buffer. Read about C dynamic memory allocation. If you are unfamiliar with C programming, that might be tricky to you. BTW, you could even consider using the Linux specific readline(3)
主要是你对C编程的熟悉程度。
注意:在 C 中,#
不是开始注释,而是 preprocessor 指令。
您将 gets
替换为 fgets
。
几乎就这么简单,区别(除了参数)是 fgets
缓冲区末尾可能有一个换行符。 (请注意,我说 可能 在那里。)