son - tipos de error en c++
Reparar fallas de segmentación en C++ (6)
Compila tu aplicación con
-g
, entonces tendrás símbolos de depuración en el archivo binario.Use
gdb
para abrir la consola de gdb.Usa el
file
y pásalo el archivo binario de tu aplicación en la consola.Use
run
y pasar en cualquier argumento que su aplicación necesite para comenzar.Haga algo para causar una falla de segmentación .
Escriba
bt
en la consola degdb
para obtener un seguimiento de pila de la falla de segmentación .
Estoy escribiendo un programa de C ++ multiplataforma para Windows y Unix. En el lado de la ventana, el código compilará y ejecutará sin problemas. En el lado de Unix, se compilará, sin embargo, cuando intento ejecutarlo, aparece un error de segmentación. Mi corazonada inicial es que hay un problema con los punteros.
¿Cuáles son las buenas metodologías para encontrar y corregir errores de fallas de segmentación?
Algunas veces el choque en sí mismo no es la verdadera causa del problema, quizás el recuerdo se rompió en un punto anterior, pero tardó un tiempo en mostrarse la corrupción. Eche un vistazo a valgrind , que tiene muchos controles para problemas de punteros (incluida la comprobación de límites de matriz). Te dirá dónde comienza el problema, no solo la línea donde ocurre el bloqueo.
Antes de que surja el problema, trate de evitarlo tanto como sea posible:
- Compila y ejecuta tu código tan a menudo como puedas. Será más fácil ubicar la parte defectuosa.
- Intente encapsular rutinas de bajo nivel / propensas a errores de modo que rara vez tenga que trabajar directamente con la memoria (preste atención a la modelización de su programa)
- Mantener un banco de pruebas Tener una visión general de lo que está funcionando actualmente, lo que no funciona más, etc., lo ayudará a descubrir dónde está el problema (la prueba Boost es una posible solución, yo no la uso, pero la documentación puede ayudar a entender de qué de información debe ser mostrada).
Use las herramientas adecuadas para la depuración. En Unix:
- GDB puede decirle dónde programa el bloqueo y le permitirá ver en qué contexto.
- Valgrind te ayudará a detectar muchos errores relacionados con la memoria.
-
Con GCC también puede usar mudflapCon GCC y Clang puede usar Address / Memory Sanitizer . Puede detectar algunos errores que Valgrind no hace y la pérdida de rendimiento es más ligera.
Finalmente, recomendaría las cosas habituales. Cuanto más legible, mantenible, claro y ordenado sea tu programa, más fácil será depurarlo.
En Unix puedes usar valgrind para encontrar problemas. Es gratis y poderoso. Si prefiere hacerlo usted mismo, puede sobrecargar los operadores nuevos y eliminar para configurar una configuración donde tenga 1 byte con 0xDEADBEEF
antes y después de cada nuevo objeto. Luego rastrea lo que sucede en cada iteración. Esto puede no captar todo (no está garantizado que incluso toque esos bytes) pero me ha funcionado en el pasado en una plataforma de Windows.
No sé de ninguna metodología para arreglar cosas como esta. No creo que sea posible encontrar uno tampoco porque el problema es que el comportamiento de su programa no está definido (no conozco ningún caso cuando SEGFAULT no haya sido causado por algún tipo de UB) .
Hay todo tipo de "metodologías" para evitar el problema antes de que surja. Uno importante es RAII.
Además de eso, solo tienes que arrojar tus mejores energías psíquicas.
Sí, hay un problema con los punteros. Es muy probable que esté utilizando uno que no se haya inicializado correctamente, pero también es posible que esté estropeando su administración de memoria con doble libre o algo así.
Para evitar punteros no inicializados como variables locales, intente declararlos lo más tarde posible, preferiblemente (y esto no siempre es posible) cuando se pueden inicializar con un valor significativo. Convénzase de que tendrán un valor antes de que se utilicen, examinando el código. Si tiene dificultades con eso, inicialícelos en una constante de puntero nulo (generalmente escrito como NULL
o 0
) y revíselos.
Para evitar punteros no inicializados como valores de miembro, asegúrese de que se inicialicen correctamente en el constructor y se manejen correctamente en los constructores de copia y los operadores de asignación. No confíe en una función de init
para la gestión de memoria, aunque puede hacerlo para otra inicialización.
Si su clase no necesita constructores de copia u operadores de asignación, puede declararlos como funciones de miembros privados y nunca definirlos. Eso causará un error de compilación si se usan explícita o implícitamente.
Use punteros inteligentes cuando corresponda. La gran ventaja aquí es que, si se adhiere a ellos y los usa consistentemente, puede evitar por completo la delete
escritura y nada se eliminará por duplicado.
Utilice cadenas de C ++ y clases de contenedor siempre que sea posible, en lugar de series y cadenas de estilo C. Considere usar .at(i)
lugar de [i]
, porque eso forzará la comprobación de límites. Vea si su compilador o biblioteca se puede configurar para verificar los límites en [i]
, al menos en el modo de depuración. Las fallas de segmentación pueden ser causadas por sobrepasados de buffer que escriben basura sobre punteros perfectamente buenos.
Hacer esas cosas reducirá considerablemente la probabilidad de fallas de segmentación y otros problemas de memoria. Sin duda, no podrán arreglar todo, y es por eso que debería usar valgrind de vez en cuando cuando no tenga problemas, y valgrind y gdb cuando lo haga.