2009-08-23 9 views
24

Una pequeña utilidad mía que hice para uso personal (escrita en C++) se estrelló al azar ayer (la he usado más de 100 horas sin problemas hasta ahora) y aunque normalmente no hago esto, me sentía un poco aventurero y quería probar y aprender más sobre el problema. Decidí entrar en el Visor de eventos de Windows y ver lo que había acumulado sobre el accidente:Análisis de un bloqueo en Windows: ¿qué nos dice el mensaje de error?

Faulting application StraightToM.exe, version 0.0.0.0, time stamp 0x4a873d19 
Faulting module name : StraightToM.exe, version 0.0.0.0, time stamp 0x4a873d19 
Exception code : 0xc0000005 
Fault offset : 0x0002d160, 
Faulting process id: 0x17b4 
Faulting application start time: time 0x01ca238d9e6b48b9. 

Mi pregunta es, ¿qué hacer cada una de estas cosas significan, y cómo iba a utilizar éstos para depurar mi programa? Esto es lo que sé hasta ahora: el código de excepción describe el error y 0xc0000005 es una violación de acceso a la memoria (intentó acceder a la memoria que no le pertenecía). Estoy específicamente interesado en saber más sobre lo siguiente:

  1. ¿Qué significa la compensación de fallas? ¿Representa eso la ubicación en el archivo donde ocurrió el error, o significa la "línea" de ensamblaje donde ocurrió el error? Conociendo la compensación de fallas, ¿cómo usaría un programa como OllyDbg para encontrar el código ensamblador correspondiente que causó el error? O, mejor aún, ¿sería posible (fácilmente) determinar qué línea de código en la fuente C++ causó este error?
  2. Es obvio que la marca de tiempo corresponde a la hora de UNIX de 32 bits en el momento del bloqueo, pero ¿qué significa el tiempo de inicio de la aplicación de 64 bits? ¿Por qué serían 64 bits si la marca de tiempo es 32?

Tenga en cuenta que soy principalmente un programador de C++, así que aunque sé algo sobre el montaje, mi conocimiento es muy limitado. Además, este realmente no es un problema grave que deba corregirse (y tampoco se reproduce fácilmente, dada la naturaleza del programa), solo lo uso como una excusa para obtener más información sobre lo que significan estos mensajes de error. La mayor parte de la información sobre estos registros de fallos que he encontrado en línea suele estar dirigida al usuario final, por lo que no me han ayudado mucho (como programador).

Gracias de antemano

+0

0xc0000005 - acceso denegado ... – Mandrake

+3

Para lectores futuros, '0xc0000005' no es acceso denegado, es 'una infracción de acceso ocurrida'. Código correcto, instalación incorrecta. El acceso denegado es el código 5 en las instalaciones de Windows, por lo que es '0x80070005', a menudo acortado a' 0x00000005'. – niemiro

Respuesta

16

La marca de tiempo de 64 bits es la secuencia de tiempo de la aplicación principal se creó en intervalos de 100 nanosegundos desde el 1 de enero de 1601 (UTC) (esto se conoce como FILETIME). La marca de tiempo de 32 bits está realmente en formato time_t (indica la hora en que se creó el módulo y se almacena en el encabezado del módulo).

Diría que 0x0002d160 es un desplazamiento de la dirección de carga del módulo (parece demasiado bajo para una dirección absoluta). Encienda Visual Studio, inicie el depurador, eche un vistazo a la ventana de depuración de "módulos". Su archivo exe debe aparecer allí. Encuentre la dirección donde se carga el módulo, agregue 0x0002d160 a esa dirección y observe el desmontaje en la dirección resultante.Visual Studio muestra el código fuente entremezclado con el ensamblaje, no debería tener problemas para averiguar qué línea fuente causó el problema.

+0

Ah ok, he oído hablar de 'FILETIME' antes, no sé por qué no uní las piezas en esta instancia. En cuanto a mirar a través de los módulos en Visual Studio, parece una forma segura de hacerlo: el único problema es que construí este programa usando MinGW. Tengo MSVC y podría reconstruir el .exe usándolo, pero supongo que el desplazamiento de falla original (generado con el ejecutable MinGW-built) no se correspondería con el exe creado por MSVC, ¿verdad? – GRB

+0

Ya veo. No, las compensaciones no corresponderían. No sé qué tipo de información de depuración genera MinGW, pero ciertamente comenzaría por buscar la utilidad 'objdump', podría identificar la rutina culpable. – avakar

+0

objdump me ayudó mucho. Después de aproximadamente una hora de experimentar con diferentes configuraciones y compilaciones de depuración (MinGW), parece que el error ocurrió con una función de biblioteca interna que estaba usando. Si bien no hay forma de saber esto con certeza, esto sugiere que fue un error en la biblioteca y no en mi código. – GRB

7

no hay mucho que vas a ser capaz de hacer la autopsia con esta información.

El bit de información útil es el código de excepción, 0xc0000005, que en este caso solo significa una infracción de acceso. Entonces eliminaste la referencia nula o algún otro trozo de memoria que no poseías.

La compensación de fallas, sospecho, es el desplazamiento desde donde se cargó su archivo DLL en la memoria, por lo que en teoría podría agregarlo a su dirección base y encontrar el código ofensivo, pero no estoy seguro.

Su mejor apuesta para la depuración es atraparlo en el depurador la próxima vez que esto suceda. Puede usar Image File Execution Options para ejecutar su aplicación automáticamente en el debugger. Asegúrate de tener los símbolos listos (considera construir DEPURACIÓN si estás utilizando LIBERACIÓN).

6

dios depuración John Robbins construyó una pequeña herramienta llamada CrashFinder para ayudar con situaciones como esta: https://www.wintellect.com/crashfinder-2-8-yes-native-code-still-lives/

Es siempre una buena idea para ahorrar PDB para cada proyecto de construcción de soltar al público (esto suena como una herramienta solo use en privado, pero podría ser una buena idea mantener los símbolos PDB para la última compilación).

+0

CrashFinder parecía muy prometedor, pero desafortunadamente no parecía funcionar. La dirección de falla original y la dirección de falla + dirección de inicio del módulo arrojaron poca información. Incluso después de crear una aplicación de prueba con un error obvio ('* (int *) 0 = 1;'), el uso de la dirección de falla proporcionada con CrashFinder en esa aplicación no funcionó. Puede tener algo que ver con los programas MinGW frente a los programas creados por MSVC. – GRB

+0

Ah, ya veo. No sé si MinGW puede generar símbolos de PDB. Sospecho que CrashFinder los necesita para ubicar la ubicación del problema. –

+1

Aparentemente no. Definitivamente necesitaría información adicional para encontrar una línea de fuente con un binario. Los PDB proporcionan esa información, en la medida de lo posible. Pero los compiladores modernos a veces lo hacen imposible: si dos funciones se asignan a las mismas instrucciones y no se comparan los punteros de función, pueden compartir la misma dirección. Si ocurre un bloqueo allí, necesitaría conocer a la persona que llama para determinar cuál de los dos se llamó. Además, después de inlinear y optimizar, el llamador y el destinatario pueden mezclarse incluso más allá del nivel de declaración de C++. – MSalters

1

Parece que todavía no hay una buena respuesta aquí, ¿qué ocurre si el bloqueo ocurre fuera del entorno de desarrollo? Creo que el conjunto es la dirección donde se bloquea el código de ensamblaje. Pero necesita saber dónde está el inicio del código de ensamblado de esa dll. o tal vez no necesita saber la dirección de inicio, porque puede usar la herramienta de ensamblaje para abrir dll y encontrar el código ensamblador agregando el desplazamiento para iniciar la dirección

+1

Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar aclaraciones de un autor, deje un comentario debajo de su publicación; siempre puede comentar sus propias publicaciones, y una vez que tenga suficiente [reputación] (http://stackoverflow.com/help/whats-reputation) lo hará poder [comentar cualquier publicación] (http://stackoverflow.com/help/privileges/comment). – Claies

+0

gracias, ahora lo entiendo – Tony

Cuestiones relacionadas