2011-08-11 13 views
7

Cppcheck muestra la siguiente advertencia para scanf:scanf Cppcheck advertencia

 
Message: scanf without field width limits can crash with huge input data. To fix this error message add a field width specifier: 
    %s => %20s 
    %i => %3i 

Sample program that can crash: 

#include 
int main() 
{ 
    int a; 
    scanf("%i", &a); 
    return 0; 
} 

To make it crash: 
perl -e 'print "5"x2100000' | ./a.out 

no puedo fallar este programa de mecanografía "enorme de datos de entrada". ¿Qué debería escribir exactamente para obtener este bloqueo? Asimismo, no entiendo el significado de la última línea de esta advertencia:

perl -e ...

+6

"Presione cualquier tecla para continuar." "¿Dónde está la clave?" – Dave

+0

@Dave: ????? Su comentario parece spam :( –

+1

¿Qué? No. Según la redacción de su pregunta, parecía que estaba malinterpretando la frase "datos de entrada enormes": no es algo que escriba, es una propiedad de la entrada. el mismo escenario que el clásico cualquier chiste clave, que estaba usando como metáfora de tu problema. – Dave

Respuesta

5

La última línea es un comando de ejemplo para ejecutar para demostrar el bloqueo con el programa de ejemplo. Básicamente, causa que perl imprima 2.100.000 veces "5" y luego lo transfiera al stdin del programa "a.out" (que se supone que es el programa de ejemplo compilado).

En primer lugar, scanf() se debe utilizar para la prueba solamente, no en programas del mundo real debido a varios problemas que no manejará correctamente (por ejemplo, pidiendo "% i" pero las entradas de usuario "12345abc" (el "abc" permanecerá en stdin y podría hacer que se rellenen las siguientes entradas sin posibilidad de que el usuario las cambie).

Al respecto de este problema: scanf() sabrá que debe leer un valor entero, sin embargo, no sabrá cuánto tiempo puede ser. El puntero podría apuntar a un entero de 16 bits, un entero de 32 bits o un entero de 64 bits o algo aún más grande (que no se sabe). Funciones con un número variable de argumentos (definido con ...) don ' t saber el tipo de datos exacto de los elementos pasados, por lo que tiene que volver a en la cadena de formato (razón por la cual las etiquetas de formato no son opcionales, como en C# donde solo las numera, p. "{0} {1} {2}"). Y sin una longitud determinada, tiene que asumir algo de longitud que también podría depender de la plataforma (lo que hace que la función sea aún más segura de usar).

En general, considérelo posiblemente nocivo y un punto de partida para los ataques de desbordamiento del búfer. Si desea proteger y optimizar su programa, comience reemplazándolo con alternativas.

+3

Scanf sabe exactamente qué tan grande puede ser el puntero: '% d' es' sizeof (int) * 8'-bit, '% ld' es' sizeof (long) * 8'-bit , Etcétera. Todos estos son conocidos en tiempo de compilación. – Dave

+0

@Dave: int n [SIZE]; memset (n, 0, sizeof (n) * sizeof (int)); –

+0

No entiendo por qué se acepta esta respuesta. no responde la pregunta. ¿Es la respuesta que scanf() supone que el número de dígitos de la cadena de entrada define el ancho de bits del entero al que está leyendo (cppreference no estaría de acuerdo con eso)? ¿O es que algunas implementaciones de scanf() tienen desbordamientos internos? – Arvid

0

Intenté funcionar la expresión Perl en contra del programa de C y lo hizo accidente aquí en Linux (fallo de segmentación)

0

El uso de la función 'scanf' (o fscanf y sscanf) en aplicaciones reales generalmente no se recomienda en absoluto porque no es seguro y suele ser un agujero para el desbordamiento del búfer si se suministran datos de entrada incorrectos. Existen formas mucho más seguras de ingresar números en muchas bibliotecas de uso común para C++ (QT, bibliotecas en tiempo de ejecución para Microsoft Visual C++, etc.). Probablemente también pueda encontrar alternativas seguras para el lenguaje C "puro".