端末で実行すると、入力がない限り、、、hexdump
などの行の先頭^D
にある単一の項目には反応しません。cat
od
bc
prompt% hexdump -C
<control-D>
prompt% hexdump -C
hello
<control-D><control-D> # a single ^D won't do
00000000 68 65 6c 6c 6f 0a |hello.|
00000006
私はこれをfedora 28とdebian 9で再現できます。hexdump
Debianから提供されていますが、bsdmainutils
bsdではこれは発生しません。
これはただのバグですか?この動作を表すことが知られている他のプログラムはありますか?
ベストアンサー1
@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() 関数のサイズ呼び出しを行う必要があり、結果はオブジェクトを正確に含む符号なし文字配列に読み込み順序で格納する必要があります。
~についてfgetc
:
stream が指す入力ストリームのファイル終了インジケータが設定されていない場合そして次のバイトが存在する場合、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ライブラリの議論で指摘したように、可能性他のCライブラリ(muslなど)や他のプラットフォームの動作に関係なく、GNU Cライブラリの特性を必要とするソフトウェアを作成してください。しかし、上記の長年の議論の間、そのような計画は確定されていません。一部のプログラムは古いGNU Cライブラリによって破損し、ユーザーはEOF信号を2回連続して送信する必要があります。持つhexdump
これには他の人も含まれます。patch
StackOverflowの2018年。