practicas - programacion en c
Cómo aprender C depuración y mejores prácticas (7)
He escrito un módulo Apache en C. Bajo ciertas condiciones, puedo obtener segfault, pero no tengo idea de por qué. En este punto, podría ser mi código, podría ser la forma en que estoy compilando el programa, o podría ser un error en la biblioteca del sistema operativo (la segfault ocurre durante una llamada a dlopen ()).
Intenté ejecutar GDB y Valgrind sin éxito. GDB me da un seguimiento en la llamada al sistema dlopen () que parece insignificante. En Valgrind, el error en realidad parece desaparecer o al menos no ser reproducible. Por otro lado, soy un novato total en lo que respecta a estas herramientas.
Soy un poco nuevo en la programación C de calidad de producción (empecé en C hace muchos años, pero nunca he trabajado profesionalmente con él). ¿Cuál es la mejor manera de aprender los mecanismos de depuración? ¿Qué otras herramientas debería estar investigando? En resumen, ¿cómo descubres cómo abordar nuevos desafíos de errores?
EDITAR: solo para aclarar, quiero agradecer la entrada de Sydius y dmckee. Eché un vistazo a la guía de Apache y estoy bastante familiarizado con dlopen (y dlsym y dlclose). Mi módulo funciona en su mayor parte (tiene aproximadamente 3k líneas de código y, siempre que no active esta sección, las cosas parecen funcionar bien).
Supongo que aquí es de donde proviene mi pregunta original: no sé qué hacer a continuación. Sé que no he usado GDB y Valgrind en todo su potencial. Sé que es posible que no esté compilando con las banderas correctas exactas. Pero estoy teniendo problemas para descubrir más. Puedo encontrar guías para principiantes que me dicen lo que ya sé, y páginas man que me dicen más de lo que necesito saber, pero sin orientación.
Consejo muy general:
Mira de nuevo a esa traza inversa. ¿Hay alguno de los marcos de pila en el código que controlas? Si es así, ¿qué línea y qué está sucediendo allí?
¿Sabes lo que hace
dlopen()
? Si no, lee el manual. Si el backtrace no incluye ninguno de sus códigos, es posible que esto esté fallando en el momento en queApache
intenta cargar su código. ¿Estás seguro de que has construido el módulo con las opciones correctas del compilador?La depuración efectiva requiere conocer su entorno y herramientas. El consejo de Sydius es bueno aquí.
Si está atascado en otras rutas, verifique que pueda escribir, cargar y ejecutar un módulo trivial. Probablemente encontrará un ejemplo de esto en casi cualquier documentación sobre el tema.
Para aclarar de Dave: entre principiante y experto puede ser un punto difícil.
¿Está llamando en bibliotecas en el código ofensivo que no usa en otro lugar? Tal vez la ruta del cargador está en mal estado solo por ese recurso.
Aparte de eso, estoy fuera de mi consejo. Lo siento.
NB: tuve ocasión de leer el libro de David J. Agans Debugging el año pasado. No es específico del software, pero es una buena lectura y útil, incluso si ya eres un buen depurador.
Eché un vistazo a la documentación de valgrind y, por defecto, no verifica los procesos secundarios. No me sorprendería en absoluto si Apache pudiera ejecutar su módulo en un hilo secundario . Por favor, inténtalo
valgrind --trace-children=yes ....
El hecho de que esté fallando en la llamada a dlopen () parece un poco sospechoso para mí. Hay varias cosas que pueden salir mal al intentar abrir un objeto compartido; pero ninguno de ellos debería causar una falla seg.
La única excepción en la que puedo pensar es un problema en la inicialización de la biblioteca del SO. Sobre esa base, sugeriría algunas cosas que podría tratar de obtener más información.
- Verifique la ruta de su biblioteca y asegúrese de que la biblioteca que está tratando de cargar se encuentre en esta ruta. (Nota: dado que está usando Apache, creo que también debe verificar la ruta de acceso de la biblioteca para el usuario bajo el cual se está ejecutando Apache. (Creo que el usuario es "nadie"). Creo que está buscando el entorno LD_LIBRARY_PATH variable.) También tenga en cuenta que si tiene múltiples versiones de la biblioteca, esto puede ser realmente importante. Asegúrese de cargar la versión correcta de la biblioteca.
- Como principio general de depuración, trate de simplificar el problema. Dado que sé muy poco sobre los módulos de Apache, trataría de eliminar a Apache de la ecuación: intente escribir un programa simple de C que haga poco más que un dlopen () y posiblemente el dlsym posterior (), luego salga. Este programa proporciona un entorno mucho más simple para solucionar problemas y / o depurar. Si este programa se ejecuta limpiamente, entonces es posible que deba examinar más detenidamente qué es diferente cuando falla el programa seg. (¿Qué está haciendo Apache de manera diferente?) Por otro lado, si su programa también segmenta las fallas, puede considerar un posible problema con la biblioteca, el compilador cambia para el programa y el código en el programa. (O todo lo anterior.)
Si bien es posible que no haya ofrecido muchos consejos de depuración para fines generales, espero que algo aquí haya sido útil.
Este enlace puede ayudar: Guía de depuración de Apache con su problema específico. La experiencia con problemas específicos es una de las mejores maneras de mejorar en el caso general.
Nuestros estudiantes que no son CS (es decir, ingeniería eléctrica, matemática, física) los recomiendo en las conferencias de programación "The Practice of Programming" de Kernighan. Es bueno ofrece algunos conceptos básicos que ayudan al desarrollo (como las pruebas y aquí viene: depuración).
Si ya eres un programador experimentado, es quizás demasiado básico para ti. Entonces tengo uno más de estos proverbios Zen para ti: "La sabiduría sin la experiencia de filtrado no tiene valor".
Una respuesta de la que solo puedo hacer una copia de seguridad: mire nuevamente el seguimiento de la pila, esta es la ayuda más relevante mediante la depuración (especialmente en los bordes, donde la ejecución cruza diferentes módulos (especialmente el suyo y los bordes de lib / OS), y mira el argumento de la función y verificar si son sanos).
Lamentablemente, las herramientas de GNU no son las mejores, y mi experiencia es que el enlazador dinámico enturbia las aguas enormemente. Si puede hacer que Apache se vincule estáticamente con su módulo, esto permitirá que gdb funcione especialmente de manera más confiable. No sé qué fácil es eso; mucho depende del sistema de compilación de Apache.
Es preocupante pero no impactante que no puedas reproducir fácilmente el error con valgrind.
En cuanto a la compilación con los indicadores correctos, tanto valgrind como gdb le darán mucha mejor información si compila todo lo que está a la vista con -g -O0
. No crea las afirmaciones en la página del manual de gcc -g -O
que gcc -g -O
es lo suficientemente bueno; no es --- incluso -O
hará que las variables en el código fuente sean eliminadas por el optimizador.
Estoy seguro de que las técnicas de depuración son, en general, independientes del lenguaje y no existe tal "depuración C".
Hay muchas herramientas diferentes que pueden ayudarlo a encontrar problemas simples como la pérdida de memoria, o simplemente errores estúpidos en el código, algunas veces incluso puede atrapar sobrecargas de memoria simples. Pero para los problemas realmente difíciles de encontrar, como los problemas originados por la multitarea / interrupción, la corrupción de la memoria dma, la única herramienta es su cerebro y un código bien escrito (con la idea de que este código será depurado). Puede encontrar más información sobre cómo preparar su código para la depuración aquí . Parece de la publicación de Sydius que Apache ya tiene un buen mecanismo de rastreo en su lugar, así que simplemente úsalo y agrega simalar a tu base de código.
Además, diría que otro paso importante en la depuración es "no asumir / pensar". Base todos sus pasos en hechos simples, demuestre todas sus suposiciones con 100% de precisión antes de dar otro paso basado en esa suposición. Basar su depuración en suposiciones generalmente lo llevará a una dirección equivocada.
Editar después de la aclaración de Dave:
El próximo paso debería ser encontrar la parte más pequeña del código que causa el problema. Te entristece que si deshabilitas cierta sección, el módulo se carga. simplemente haga que esta sección sea lo más pequeña posible, elimine / moke todo en la sección hasta que encuentre idealmente una línea que haga que el módulo no se cargue. Y después de encontrar esta línea. será el momento exacto para comenzar a usar tu cerebro :) Simplemente no olvides verificar al 100% que esta es la línea .