GNU/Linux >> Znalost Linux >  >> Linux

Proč se hexdump pokouší číst přes EOF?

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.


Linux
  1. Čte Tail celý soubor?

  2. Proč nemají Ifs žádný účinek v `když Ifs=číst...`?

  3. Proč možnost Ssh -t přidává Cr &Lf do přesměrovaného výstupu?

  1. Proč variabilní expanze bez $ funguje ve výrazech?

  2. Proč to „při čtení“ funguje v terminálu, ale ne ve skriptu Shell?

  3. Proč má „/“ položku „...“?

  1. Proč se v Linuxu používá select

  2. Co dělá povolení k provedení?

  3. Proč síťový provoz Linuxu prochází pouze přes eth0?