2011-04-28 12 views
5

Acabo de pasar algún tiempo persiguiendo un error que se reduce a lo siguiente. El código sobrescribió erróneamente la pila, y creo que se escribió sobre la dirección de retorno de la llamada a la función. Después de la devolución, el programa fallaría y la pila estaría dañada. Al ejecutar el programa en valgrind devolvería un error como:Cómo depurar errores de sobreescritura de la pila con Valgrind?

vex x86->IR: unhandled instruction bytes: 0xEA 0x3 0x0 0x0 
==9222== valgrind: Unrecognised instruction at address 0x4e925a8. 

Calculo que esto es debido a que el rendimiento subió a un lugar al azar, que contiene cosas que no eran válidos los códigos de operación x86. (Aunque yo soy de alguna manera sospechoso que esta dirección 0x4e925a8 se encontraba en una página ejecutable. Imagino valgrind arrojaría un error diferente si este no era el caso.)

Estoy seguro de que el problema era de la stack- sobreescribiendo el tipo, y desde entonces lo he arreglado. Ahora estoy tratando de pensar cómo podría detectar errores como este de manera más efectiva. Obviamente, valgrind no puede advertirme si reescribo los datos en la pila, pero tal vez pueda detectarse cuando alguien escribe sobre una dirección de retorno en la pila. En principio, puede detectar cuándo algo como 'push EIP' ocurre (para que pueda indicar dónde están las direcciones de retorno en la pila).

Me preguntaba si alguien sabe si Valgrind, o cualquier otra cosa puede hacer eso? De lo contrario, puede comentar otras sugerencias sobre errores de depuración de este tipo de manera eficiente.

+0

Le recomiendo que presente un error de lista de deseos contra valgrind. –

+0

La dirección de retorno no se presiona con la instrucción 'push', sino implícitamente con la instrucción' call'. Lo que hace que sea más fácil detectar dónde está. –

+0

@ Jan Hudec, eso sería una buena característica en Valgrind, ¿no? Sí, tiene razón en que 'call' empuja la dirección de retorno, la escribí de esta manera solo para ser completamente clara. – Max

Respuesta

4

Si el problema se repite lo suficiente de manera determinista que se pueden señalar en particular la función que tiene su pila rota (en un caso de prueba repetible), usted podría, en GDB:

  1. Rotura en la entrada a esa función
  2. Buscar donde se almacena la dirección de retorno (es relativo a %ebp (en x86) (que guarda el valor de %esp en la entrada de la función), no estoy seguro de si hay algún desplazamiento).
  3. Agregue el punto de observación a esa dirección. Debe emitir el comando watch con un número calculado, no una expresión, porque con una expresión, gdb intentaría volver a evaluarlo después de cada instrucción en lugar de configurar una trampa, lo que sería extremadamente lento.
  4. Deje que la función se ejecute hasta su finalización.

Todavía no he trabajado con el soporte de python disponible en gdb7, pero debería permitir la automatización de esto.

+0

Gracias por su respuesta, lo acepto a menos que aprendo algo aún mejor :) – Max

5

En general, la detección Valgrind de desbordamientos en la pila y las variables globales es débil a inexistente. Podría decirse que Valgrind es la herramienta incorrecta para ese trabajo.

Si se encuentra en una de las plataformas soportadas, edificio con -fmudflap y la vinculación con -lmudflap le dará resultados mucho mejores para este tipo de errores. Documentos adicionales here.

Udpdate:

Mucho ha cambiado en los últimos 6 años desde que esta respuesta. En Linux, , la herramienta para encontrar desbordamientos de pila (y de pila) es AddressSanitizer, compatible con las versiones recientes de GCC y Clang.

+0

Parece que el http://www.stlinux.com/devel/debug/mudflap es un enlace inactivo. Quizás este enlace se puede utilizar en su lugar: https://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging – bgoodr

+1

@bgoodr He actualizado la respuesta: mudflap es mucho más débil y tiene mucha más memoria por encima, en comparación con el estado actual de la técnica. –

+0

¡Gracias por ese consejo sobre la carga de la memoria! – bgoodr

Cuestiones relacionadas