2010-09-15 17 views
46

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.Corrección de fallas de segmentación en C++

¿Cuáles son las buenas metodologías para encontrar y corregir los errores de fallas de segmentación?

Respuesta

71
  1. compilar su aplicación con -g, entonces tendrá símbolos de depuración en el archivo binario.

  2. Utilice gdb para abrir la consola de gdb.

  3. Usa file y pásalo el archivo binario de tu aplicación en la consola.

  4. Use run y pase los argumentos que su aplicación necesite para comenzar.

  5. Haga algo para causar un error de segmentación .

  6. Tipo bt en la consola gdb para obtener un seguimiento de la pila de la segmentación de fallos.

2

En Unix puede 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 objeto nuevo. 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.

+1

bien esto sería 4 bytes en lugar de 1 ... pero el principio está bien. –

+0

¿Puedo hacer un enlace a mi [depurador de montón no intrusivo] (http://stackoverflow.com/questions/2835416)? :-) – fredoverflow

+0

Vaya por ello. Nos dedicamos a ayudar a los demás aquí para que todo lo que pueda ayudar se agregue. – wheaties

22

En ocasiones, el bloqueo en sí mismo no es la verdadera causa del problema, quizás la memoria se rompió en un punto anterior, pero tardó un tiempo en mostrarse la corrupción. Consulte valgrind, que tiene muchas comprobaciones de 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 se produce el bloqueo.

14

antes de que surja el problema, trate de evitar tanto como sea posible:

  • compilar y ejecutar código tan a menudo como sea posible. Será más fácil ubicar la parte defectuosa.
  • Trate de 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)
  • Mantenga 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 (Boost test es una solución posible, yo no la uso, pero la documentación puede ayudar a entender qué tipo de la información debe ser mostrada).

Utilice 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 le ayudará a detectar muchos errores relacionados con la memoria.
  • Con GCC también puede usar mudflap Con 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.

0

No sé de cualquier metodología a utilizar para fijar este tipo de cosas. 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, sólo hay que tirar sus mejores energías psíquicas en ella.

2

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 alguna dificultad con eso, inicializarlas a una constante puntero nulo (generalmente escrita como NULL o 0) y comprobar ellos.

Para evitar punteros no inicializados como valores de miembros, asegurarse de que estén inician correctamente en el constructor, y se maneja apropiadamente de constructores de copia y operadores de asignación. No confíe en una función init para la administración de memoria, aunque puede hacerlo para otra inicialización.

Si su clase no necesita constructores de copia o los operadores de asignación, se puede declarar como funciones miembro privadas y nunca definirlos. Eso causará un error de compilación si se usan explícita o implícitamente.

utilizar punteros inteligentes cuando corresponda. La gran ventaja aquí es que, si los respeta y los usa consistentemente, puede evitar escribir por completo delete y no se eliminará por duplicado.

Utilice C++ cuerdas y clases de contenedores siempre que sea posible, en lugar de cadenas estilo C y matrices. Considere usar .at(i) en lugar de [i], porque eso forzará la comprobación de límites. Vea si su compilador o biblioteca pueden configurarse para verificar límites en [i], al menos en 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 que reducirá considerablemente la probabilidad de fallos 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.

Cuestiones relacionadas