ヒントをくれた @JdeBP のおかげで、hexdump
と同じことを行う小さなテストケースを作成できました。 :
#include <stdio.h>
int main(void){
char buf[64]; size_t r;
for(;;){
printf("eof=%d, error=%d\n", feof(stdin), ferror(stdin));
r = fread(buf, 1, sizeof buf, stdin);
printf("read %zd bytes, eof=%d, error=%d\n",
r, feof(stdin), ferror(stdin));
if(!r) return 0;
}
}
glibc ベースのシステム (典型的な Linux デスクトップ) で実行する場合。
prompt$ ./fread-test
eof=0, error=0
<control-D>
read 0 bytes, eof=1, error=0
prompt$ ./fread-test
eof=0, error=0
hello
<control-D>
read 6 bytes, eof=1, error=0
eof=1, error=0
<control-D>
read 0 bytes, eof=1, error=0
bsd、solaris、busybox (uclibc)、android などで実行する場合:
prompt$ ./fread-test
eof=0, error=0
hello
<control-D>
read 6 bytes, eof=1, error=0
eof=1, error=0
read 0 bytes, eof=1, error=0
標準の私の不慣れな解釈に基づくと、これはバグのように見えます glibc (GNU C ライブラリ) で。
fread
について :
オブジェクトごとに、サイズの呼び出しが fgetc() 関数に対して行われ、その結果が、オブジェクトを正確にオーバーレイする unsigned char の配列に read の順序で格納されます。
fgetc
について :
bystream を指す入力ストリームのファイル終了インジケータが設定されていない場合 次のバイトが存在する場合、fgetc() 関数は次のバイトを取得します
eof インジケータが設定されていても、glibc は「次のバイトを取得」しようとするようです。
確かに、実際に GNU C ライブラリのバグであり、BSD または musl C ライブラリには存在しません。これは 2005 年に知られていました。Ulrich Drepper は 2007 年にバグを修正せずにバグ レポートを閉じました。2012 年に議論され、他の C ライブラリにはこの動作がなく、また、1999 年の C 標準はかなりそれについて具体的であり、Solaris には、c99
のときに呼び出されるこのための特別なメカニズムさえあります。 cc
の代わりにコンパイラとして使用されます .
2018 年に最終的に修正されました。修正は GNU C ライブラリのバージョン 2.28 にあります。 Debian の現在の「安定した」バージョンであるバージョン 9 は、GNU C ライブラリのバージョン 2.24 にあり、このバグは報告されてから 14 年経っても現れ続けています。
GNU C ライブラリの議論で述べたように、可能性があります。 musl などの他の C ライブラリや他のプラットフォームでの動作に関係なく、GNU C ライブラリの癖を必要とするように作成されたソフトウェアのことです。しかし、前述の何年にもわたる議論では、そのようなプログラムは特定されませんでした。古い GNU C ライブラリによって破損しているいくつかのプログラムでは、ユーザーに 2 回連続して EOF を通知する必要があるため、 特定された;とりわけ hexdump
を含む ここと patch
2018 年に StackOverflow で。