Il modo più sicuro per leggere un int32 in C

1

Stavo discutendo del sottile problema che puoi affrontare quando scrivi in C, quindi (per divertimento) ho iniziato a creare un codice antiproiettile in grado di leggere un intero 32 bit dallo stdin.

Ho scritto questo codice:

#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sysexits.h>


void flush_stdin()
{   int c;
    while ((c = getchar()) != '\n' && c != EOF);
}


int32_t readInt32() 
{
    char line[13]; // -2147483648\n
#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sysexits.h>


void flush_stdin()
{   int c;
    while ((c = getchar()) != '\n' && c != EOF);
}


int32_t readInt32() 
{
    char line[13]; // -2147483648\n%pre%
    int32_t n = 0;
    if (fgets(line, sizeof(line), stdin)) {
        if (sscanf(line, "%d", &n) == 1) {
            if ((line[0] == '-' && n > 0) || (line[0] != '-' && n < 0)) {
                fprintf(stderr, "Overflow detected\n");
                exit(EX_DATAERR);
            }
            if (feof(stdin))
                flush_stdin();
            return n;
        }
    }
    fprintf(stderr, "Error: wrong int32\n");
    exit(EX_DATAERR);
}


int main() 
{
    int32_t r;
    r = readInt32();
    printf("read %d\n", r);
    return 0;
}
int32_t n = 0; if (fgets(line, sizeof(line), stdin)) { if (sscanf(line, "%d", &n) == 1) { if ((line[0] == '-' && n > 0) || (line[0] != '-' && n < 0)) { fprintf(stderr, "Overflow detected\n"); exit(EX_DATAERR); } if (feof(stdin)) flush_stdin(); return n; } } fprintf(stderr, "Error: wrong int32\n"); exit(EX_DATAERR); } int main() { int32_t r; r = readInt32(); printf("read %d\n", r); return 0; }

È davvero a prova di proiettile come penso? Hai qualche consiglio su questo codice?

Lo svantaggio principale è che tronca il primo 13 byte del tuo input, quindi se fornisci qualcosa come 000000000000001 legge 0.

EDIT:

questo codice funziona come previsto solo se si genera un eseguibile a 64 bit, ma la soluzione fornita da @Colin è migliore ...

    
posta packmad 24.03.2017 - 11:48
fonte

1 risposta

3

Sono sicuro che puoi aggiungerne altri per renderlo sicuro più , ma un'altra opzione potrebbe essere:

  1. Leggi il valore come int64
  2. Verifica che il valore sia compreso nell'intervallo compreso tra min_int32 e max_int32
  3. se il valore si trova nell'intervallo della copia in una variabile int32, altrimenti restituisce una condizione di errore.

Il tuo codice così com'è (e come lo hai verificato) contiene un possibile overflow di interi. Questo di per sé è tecnicamente un "comportamento indefinito" e, come tale, non si può fare affidamento sul comportamento del compilatore o del codice.

    
risposta data 24.03.2017 - 12:04
fonte

Leggi altre domande sui tag