stdio过滤器在管道中崩溃
问题描述:
我已经使用strfry编写了一个字符串字符串程序。它的默认标准输入工作很大,但与标准输入输出重定向使用时崩溃(功能,但内存设计缺陷末):stdio过滤器在管道中崩溃
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/mman.h"
int main(int argc,char *argv[]) {
FILE *fryend=stdin;
if (argc==1) goto mainloop;
if (argc>1) fryend=fopen(argv[1],"r") ? fryend : stdin;
mainloop:;
char *buf=malloc(4096);
while (!ferror(fryend)) {
memset(buf,0,4096);
strfry(fgets(buf,4095,fryend));
fputs(buf,stdout);
}
free(buf);
if (fryend!=stdin) fclose(fryend);
return 0;
}
这里有什么问题?使用GNU libc/GCC。通过valgrind运行,没有检测到内存泄漏。
答
fgets
返回NULL
到达文件末尾时。您应该使用此返回值而不是调用ferror
或feof
来控制您的循环。您还应该小心,不要将NULL
指针传递给字符串函数。他们可能会优雅地处理,但通常不会。
所以,你的循环应该是这样的:
while (fgets(buf, 4096, fryend)) {
strfry(buf);
fputs(buf, stdout);
}
我已经抛出了memset
,因为fgets
结果是空值终止,不会溢出缓冲区,这样你就可以通过完整的4096字节长度。
答
改写这一行
if (argc>1) fryend=fopen(argv[1],"r") ? fryend : stdin;
没有条件运算符。
也许像
if (argc > 1) {
FILE *tmp = fopen(argv[1], "r");
if (tmp) fryend = tmp;
}
答
当重定向stdin
a.out <test.txt
fgets()
可能返回NULL
。
man fgets()
来自:
返回值
[...]与fgets()的返回[S] [...]上错误NULL或当文件的端发生,而没有字符已被阅读。
反过来NULL
被传递给strfry()
,
strfry(fgets(buf, 4095, fryend));
这是不是一个好主意。
你的'fgets'调用总是在'stdin'上工作。如果'fryend'是一个文件,你应该'fclose',否则Valgrind会抱怨。我不确定''strfry'在NULL输入上的行为如何。我认为分离'fgets'和'strfry'调用并检查'NULL'是更清晰的。 – 2014-12-07 09:18:12
作为一个方面说明:在我看来,让一个失败的fopen无声地回落到stdin并不是一个好设计。 – 2014-12-07 09:19:33
@M Oehm:这是一个stdio过滤器,就像'rev'一样,所以回退到'stdin'是合理的。 – 2014-12-07 09:37:52