GNU/Linux >> Linux Esercitazione >  >> Linux

Perché hexdump tenta di leggere attraverso EOF?

Grazie a @JdeBP per il suggerimento, sono stato in grado di creare un piccolo testcase che funziona come 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;
        }
}

Quando viene eseguito su un sistema basato su glibc (tipico desktop 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

Quando eseguito su bsd, solaris, busybox (uclibc), android, ecc:

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

Sulla base della mia inesperta interpretazione dello standard, sembra un bug in glibc (la libreria GNU C).

A proposito di fread :

Per ogni oggetto, devono essere effettuate chiamate di dimensione alla funzione fgetc() e i risultati memorizzati, nell'ordine letto, in un array di caratteri senza segno che si sovrappongono esattamente all'oggetto.

Informazioni su fgetc :

Se l'indicatore di fine file per il flusso di input puntato su bystream non è impostato ed è presente un byte successivo, la funzione fgetc() otterrà il byte successivo

Sembra che glibc tenterà di "ottenere il byte successivo" anche se l'indicatore eof è impostato.

In effetti, lo è davvero un bug nella libreria GNU C, non presente nelle librerie BSD o musl C. Era noto nel 2005. Ulrich Drepper ha chiuso la segnalazione di bug senza correggere il bug nel 2007. Se ne è discusso nel 2012, dove è stato notato che altre librerie C non avevano e non hanno questo comportamento, che lo standard C del 1999 è abbastanza specifico al riguardo, e che Solaris ha anche un meccanismo speciale per questo che viene invocato quando c99 è usato come compilatore invece di cc .

È stato finalmente risolto nel 2018. La correzione è nella versione 2.28 della libreria GNU C. L'attuale versione "stabile" di Debian, la versione 9, è sulla versione 2.24 della libreria GNU C, e questo bug continua quindi a manifestarsi, 14 anni dopo essere stato segnalato.

Come notato nelle discussioni sulla libreria GNU C, c'è la possibilità di software che sono stati scritti per richiedere le stranezze della libreria GNU C senza tener conto di altre librerie C come musl o il comportamento su altre piattaforme. Tuttavia, nelle discussioni summenzionate nel corso degli anni non è stato individuato alcun programma di questo tipo. Considerando che diversi programmi che sono rotti dalla vecchia libreria GNU C, per richiedere agli utenti di segnalare EOF due volte di seguito, hanno stato identificato; incluso tra gli altri hexdump qui e patch su StackOverflow nel 2018.


Linux
  1. Tail legge l'intero file?

  2. In `mentre Ifs=Leggi..`, perché Ifs non ha alcun effetto?

  3. Perché l'opzione Ssh -t aggiunge Cr e Lf nell'output reindirizzato?

  4. Perché l'espansione della variabile senza $ funziona nelle espressioni?

  5. Perché `esce &` non funziona?

Perché tutti dovrebbero provare a usare Linux

Perché l'uomo stampa "gimme Gimme Gimme" alle 00:30?

Linux – Perché Setuid non funziona??

Perché Mv(1) copia gli oggetti se l'autorizzazione a spostarsi è negata?

Perché Unix Time inizia al 1970-01-01?

Perché questo "durante la lettura" funziona in un terminale, ma non in uno script di shell?