Díky @JdeBP za nápovědu se mi podařilo vytvořit malý testovací případ, který funguje stejně jako 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;
}
}
Při spuštění na systému založeném na glibc (typický linuxový desktop).
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
Při spuštění na bsd, solaris, busybox (uclibc), android atd.:
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
Na základě mého neodborného výkladu normy to vypadá jako chyba v glibc (knihovna GNU C).
O fread
:
Pro každý objekt se provede volání funkce fgetc() a výsledky se uloží v pořadí čtení v poli znaků bez znaménka, které přesně překrývají objekt.
O fgetc
:
Pokud není nastaven indikátor konce souboru pro vstupní proud směřující na vedlejší proud a je přítomen další bajt, funkce fgetc() získá další bajt
Zdá se, že glibc se pokusí "získat další bajt", i když je nastaven indikátor eof.
Opravdu, ve skutečnosti je chyba v knihovně GNU C, která se nevyskytuje v knihovnách BSD nebo musl C. Vědělo se o tom v roce 2005. Ulrich Drepper uzavřel zprávu o chybě bez opravy chyby v roce 2007. Diskutovalo se o tom v roce 2012, kde bylo poznamenáno, že jiné knihovny C neměly a nemají toto chování, že standard 1999 C je docela specifické a že Solaris má pro to dokonce speciální mechanismus, který se spustí, když c99
se používá jako kompilátor místo cc
.
To bylo konečně opraveno v roce 2018. Oprava je ve verzi 2.28 knihovny GNU C. Aktuální "stabilní" verze Debianu, verze 9, je na verzi 2.24 knihovny GNU C, a tato chyba se tedy nadále projevuje i 14 let po nahlášení.
Jak bylo uvedeno v diskusích o knihovně GNU C, existuje možnost softwaru, který byl napsán tak, aby vyžadoval zvláštnosti knihovny GNU C bez ohledu na jiné knihovny C, jako je musl nebo chování na jiných platformách. Ve výše uvedených diskusích v průběhu let však žádný takový program nebyl identifikován. Zatímco několik programů, které jsou poškozeny starou knihovnou GNU C, které vyžadují, aby uživatelé signalizovali EOF dvakrát za sebou, mají byl identifikován; včetně mimo jiné hexdump
zde a patch
na StackOverflow v roce 2018.