La forma más segura de leer un int32 en C

1

Estaba discutiendo sobre el problema sutil que puedes enfrentar cuando escribes en C, así que (por diversión) comencé a crear un código a prueba de balas que puede leer un entero de 32 bits desde la entrada estándar.

Escribí este código:

#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; }

¿Es realmente a prueba de balas como creo? ¿Tienes algunos consejos sobre este código?

El principal inconveniente es que trunca los primeros 13 bytes de su entrada, por lo que si proporciona algo como 000000000000001, lee 0.

EDITAR:

este código funciona como se espera solo si genera un ejecutable de 64 bits, pero la solución proporcionada por @Colin es mejor ...

    
pregunta packmad 24.03.2017 - 11:48
fuente

1 respuesta

3

Estoy seguro de que puedes agregar más para protegerlo y hacer que sea la mayoría segura, pero otra opción podría ser:

  1. Lee el valor como un int64
  2. Verifique que el valor esté dentro del rango min_int32 - max_int32
  3. si el valor está dentro del rango de la copia a una variable int32, de lo contrario devolverá una condición de error.

Su código tal como está (y como lo ha comprobado) contiene un posible desbordamiento de enteros. Esto en sí mismo es técnicamente "comportamiento indefinido", y como tal, no puedes confiar en que el compilador o el código se ejecute.

    
respondido por el Colin Cassidy 24.03.2017 - 12:04
fuente

Lea otras preguntas en las etiquetas