2011-06-23 7 views
5

Mi programa usa una biblioteca de tercera parte que arroja un fallo de segmentación en algún momento. Traté de compilar la biblioteca con símbolos de depuración y sin optimización del compilador, y el fallo desapareció. Mi sospecha es que las optimizaciones del compilador revelaron este error. ¿Cuáles son las mejores prácticas para depurar casos como este?¿Cuáles son las mejores prácticas para encontrar un error en un programa C que solo aparece en la compilación optimizada

EDITAR - (corregido la declaración anterior: "revelado" en lugar de "causado")

Creo que fue mal interpretado. No tenía la intención de culpar al compilador, o algo así. Solo pedí mejores prácticas para encontrar un error en una situación así, en la que no tengo símbolos de depuración en la biblioteca de terceros (la cola inversa conduce a la biblioteca de terceros).

+9

Mala suposición: generalmente> 99% del tiempo el problema será un error latente en el código que solo aparece cuando la optimización está habilitada. Los errores del compilador son relativamente raros en comparación con los errores en el código de usuario. –

+0

¿Por qué crees específicamente que esto es optimización del compilador? Un error de puntero flotante u otro problema de acceso a la memoria, por ejemplo, es probable que se manifieste de maneras muy diferentes cuando cambie los indicadores que usa para compilar/vincular el programa. –

+2

El error es ** NO ** en la biblioteca de terceros. Si hago un programa y falla cuando 'printf', mi primer pensamiento no es que' printf' tenga un error. – pmg

Respuesta

8

Lo que usted describe es bastante común. Y casi nunca es un error en la optimización del compilador. La optimización hace muchas cosas con tu código. Las variables se reordenan/optimizan, etc. Si tiene un desbordamiento de búfer, podría desbordar la memoria, eso no es gran cosa en la compilación de depuración, pero esa memoria es muy importante en la compilación de optimización.

Utilice valgrind para localizar errores de memoria: casi siempre son la causa de los síntomas que ve.

+0

+1 para valgrind. Úselo antes de enloquecer depurando a mano. Además, si el código es segfaulting, la ejecución de la aplicación desde dentro de GDB debe dar una referencia a dónde está ocurriendo en el código el segfault. Incluso sin símbolos de depuración, puede deducir la ubicación de la función + desplazamiento del conjunto. – gravitron

8

Su sospecha es que la optimización causó un error. Mi sospecha es que su código tiene construcciones que conducen a un comportamiento no definido, y cuando el optimizador está activado, este comportamiento indefinido se manifiesta como un comportamiento erróneo o falla. No culpes al optimizador. Encontrar UB en tu código ... puede ser complicado, sin embargo. Posibles culpables:

  • OutOfBounds índice
  • Volviendo la dirección de un temprorary
  • Un trillón de otras cosas
+2

Siempre me desconcierta cuando los programadores nuevos creen que descubrieron un error en un compilador que se ha mejorado constantemente durante más de 15 años con sus 3 declaraciones 'printf' ... – Blindy

+0

Consulte mi edición. – spektom

+0

@spektom: la ** mejor ** práctica es escribir código seguro con un comportamiento definido en primer lugar. No puedo darle un algoritmo para encontrar errores en su código, lo siento –

2

seguir poniendo instrucciones de depuración o los cuadros de mensajes en el lugar que pensar en el código se bloquea. El bloqueo se producirá entre dos cuadros de mensajes y esto lo ayudará a localizar el código defectuoso siempre que el código no haya cambiado demasiado.

También comente los bloques de código hasta que deje de producirse el bloqueo. Siga comentando hasta que vuelva la falla. Lo que ha comentado por última vez debe estar causando el bloqueo, directa o indirectamente.

Ambos métodos son útiles para la depuración general y la mitad de su trabajo ya está hecho si puede reproducir el bloqueo de manera confiable.

No proporcioné consejos específicos para la depuración de optimizaciones del compilador porque es muy poco probable que el bloqueo sea causado por eso. Las optimizaciones generalmente se prueban de forma muy robusta para garantizar que no cambien la función o la semántica del código de ninguna manera.

0

Bueno, pasar por el binario compilado no va a ayudar.

Eso deja pasar su código para descubrir qué parte está causando la segfault. Simplemente trabajaría con tu código manualmente y comenzaría a comentar cosas. Una vez que encuentre lo que está causando el error, podrá determinar qué hacer con él. Puede valer la pena agregar printf s en ubicaciones seleccionadas para ver exactamente dónde falla el programa.

pensar en ella como hacer una búsqueda binaria para el error;)

+0

En mi trabajo, hacemos una pregunta similar en las entrevistas y su respuesta es común, pero se considera una advertencia. No es que su solución finalmente no funcione, pero hay formas mucho más rápidas de encontrar una segfault (valgrind y ejecución dentro de un depurador). – gravitron

+0

Sin duda, depende del tamaño y la complejidad de su programa y de lo bueno que sea para depurar las cosas manualmente. Para mí, es la diferencia entre usar un ábaco y una calculadora. El usuario de la calculadora siempre obtendrá la respuesta correcta con bastante rapidez, pero será superado por un usuario de ábaco experimentado el 99% del tiempo: P – tskuzzy

+0

¿Ha depurado una segfault con gdb? gdb myprog; correr; ; bt <- imprime la línea de tu error. No hay forma posible de comentar/printf la solución sería más rápida. – gravitron

4

Compilar con símbolos de depuración y optimización del compilador, "con suerte" fallará también. Permita que el sistema genere un archivo central (ulimit -c unlimited, luego vuelva a ejecutar el programa). Cargue el archivo core en gdb para ver qué sucedió.

Otra herramienta poderosa es valgrind, ejecute su programa dentro de valgrind con la opción --db-attatch=yes parará y ejecutará el depurador tan pronto como detecte una lectura o escritura no válida. Las lecturas/escrituras no válidas pueden provocar Segfault, e incluso si no lo hacen, deben eliminarse de todos modos.

Buena suerte,

+0

Sí, los símbolos de depuración y la optimización no son mutuamente excluyentes (aunque las compilaciones optimizadas para la depuración todavía pueden ser un desafío). La presencia o ausencia de símbolos de depuración * * no cambia la generación del código. – caf

2

Si la traza inversa conduce a la biblioteca de terceros, utilice gdb de romper antes de la llamada a la librería. Verifique que los parámetros que está pasando a la biblioteca son válidos (es decir, no son punteros no inicializados, no son punteros a memoria libre, no están fuera de rango, etc.)

Puede usar strace rastrear las llamadas a funciones y luego intentar determinar la ruta de ejecución en la biblioteca de terceros? Use un printf o alguna otra llamada al sistema antes de la llamada fallida de la biblioteca para que tenga un punto de partida en la salida strace.

Si realmente crees que es un error en la biblioteca de terceros, deberás compilarlo con las optimizaciones para que puedas reproducir el error. ¿Estás diciendo que tu compilador solo puede incluir símbolos de depuración para compilaciones no optimizadas? gdb aún debería funcionar para compilaciones optimizadas.

0

Si solo explota al activar la optimización, entonces es un fuerte indicio de que ha invocado un comportamiento indefinido en alguna parte. Desafortunadamente, ese UB puede estar en ninguna parte cerca del código que realmente generó el segfault (como he descubierto varias veces en el pasado).

Cada vez que esto me ha sucedido a mí (que no ha sido tan frecuente), la causa fue un desbordamiento del búfer en otro lugar en el código. Sin embargo, nunca desarrollé una técnica repetible y generalmente aplicable para encontrar el problema (a menos que desee llamar a las horas que pasan por un depurador y jurar una técnica generalmente aplicable).

Cuestiones relacionadas