validaciones - ¿Qué funciones de C/C++ se usan con mayor frecuencia de forma incorrecta y pueden provocar desbordamientos de búfer?
validar entrada de datos (11)
Me han pedido que mantenga una gran base de código C ++ llena de pérdidas de memoria. Mientras hurgaba, descubrí que tenemos muchos desbordamientos de búfer que conducen a fugas (cómo se volvió tan malo, no quiero saber nunca).
Decidí eliminar los desbordamientos del búfer primero, comenzando con las funciones peligrosas. ¿Qué funciones de C / C ++ se usan con mayor frecuencia de forma incorrecta y pueden provocar un desbordamiento del búfer?
Para el compilador y / o las herramientas utilizadas para ayudar a buscar el desbordamiento del búfer, he creado otra pregunta que trata sobre esto
¿Qué versión de Visual Studio estás usando? En 2008, con todas las advertencias habilitadas, todas las funciones que menciona (y más) le advierten que están en desuso.
¿Quizás podría verificar que todas las advertencias estén activadas y dejar que el compilador haga el trabajo duro por usted?
Como nota al margen, el excelente código de seguridad de escritura hace un gran trabajo al explicar las diferentes trampas de algunas de las funciones más antiguas.
Aquí hay algunas funciones que encontré que son peligrosas:
- gets () - No verifica la longitud de la variable y puede sobrescribir la memoria si la entrada es más grande que el buffer de la variable.
- scanf () - Estoy tan contento de que Visual Studio me haya dicho que esta función está en desuso. Esta fue una solución fácil.
- strcpy (): si el espacio de la memoria de la fuente es mayor que el del destino, los datos posteriores al destino se sobrescribirán.
Básicamente, cualquier cosa que acepte un puntero y le escriba, sin verificar la longitud. Así que algo como strcpy (), sprintf () etc.
De alguna manera tengo el mismo problema en la base de código en la que trabajo. Mi consejo: desconfíe de cualquier función C que parezca str * () y mem * (). También tenga cuidado con cualquier cosa que lleve un puntero a un buffer, sin una longitud. Como parece que tienes la oportunidad de usar C ++, en los casos más atroces trataría de usar contenedores C ++ para cosas: vector, cadena, mapa, etc. Esto te facilitará la vida.
Además, las herramientas de detección automática de problemas son maravillosas. Si puede usar valgrind lo recomendaría. También Rational Purify es extremadamente poderoso, aunque no es barato.
Desafortunadamente, cualquier matriz puede provocar un desbordamiento del búfer:
uint32_t foo[3];
foo[3] = WALKED_OFF_END_OF_ARRAY;
En términos de funciones, sprintf caminará alegremente al final del buffer. Puede ser reemplazado por snprintf.
El siguiente enlace debería darle una visión completa de las funciones de seguridad en C ++ (las que se corrigen posteriormente con ''_s'' para corregir problemas como desbordamientos): http://msdn.microsoft.com/en-us/library/8ef0s5kh ( VS.80) .aspx
EDITAR: Este enlace contiene las funciones específicas que se han reemplazado: http://msdn.microsoft.com/en-us/library/wd3wzwts(VS.80).aspx
EDIT: debo mencionar que estos son métodos de Microsoft, pero el enlace sigue siendo útil para identificar funciones que se consideraron una señal de alerta.
La pregunta está comenzando en el lado equivocado, me temo. Se presume que los desbordamientos del búfer ocurren en otras funciones. La causa más común es operator ++, en mi experiencia, o como alternativa, ¡falta de operador! =.
La mejor solución para encontrar un lote de estos es / GS en Visual Studio 2005/8. No los encontrará a todos, pero es una forma económica de reducir la cantidad de trabajo manual que se necesita.
Memcpy () es otro peligroso.
Cualquier bucle que acceda a una matriz es un punto peligroso, ya que no se detiene más allá del final de la matriz.
Las pérdidas de memoria se producen al asignar memoria y no liberarla. El constructor y los destructores deberían ser otro punto fuerte de revisión, el último para asegurarse de que cualquier memoria asignada se haya liberado.
Valgrind es tu nuevo mejor amigo.
valgrind --tool = memcheck --leak-check = lleno ./a.out
En general, cualquier función que no verifica los límites en los argumentos. Una lista sería
- obtiene ()
- scanf ()
- strcpy ()
- strcat ()
Debe usar versiones de tamaño limitado como stncpy, strncat, fgets, etc. Luego, tenga cuidado al dar el límite de tamaño; tome en consideración el ''/ 0'' que termina la cadena.
Además, las matrices NO están vinculadas comprobadas en C o C ++. El siguiente ejemplo causaría errores. Ver por error
int foo[3];
foo[3] = WALKED_OFF_END_OF_ARRAY;
editar : respuestas copiadas de @MrValdez, @Denton Gentry
Un gotcha adicional en C es la función "strncpy ()". Muchas personas no se dan cuenta de que es libre devolver una cadena que no tiene terminación nula.