Me encuentro con un choque extraño en nuestro software y tengo muchos problemas para depurarlo, y entonces estoy buscando el consejo de SO sobre cómo abordarlo.¿Cómo puedo depurar una falla difícil de reproducir sin una pila de llamadas útil?
El accidente es una violación de acceso de leer un puntero NULL:
Excepción de primera oportunidad en $ 00CF0041. Clase de excepción $ C0000005 con mensaje 'infracción de acceso en 0x00cf0041: lea de la dirección 0x00000000'.
Sucede solo 'a veces' - No he logrado encontrar ninguna rima o razón, sin embargo, para cuándo - y solo en el hilo principal. Cuando esto ocurre, la pila de llamadas contiene una entrada incorrecta:
Para el hilo principal, que se trata, debe mostrar una gran pila de artículos de todo tipo.
En este punto, todos los otros subprocesos están inactivos (la mayoría se encuentra en WaitForSingleObject
o una función similar). Solo he visto este bloqueo en el hilo principal. Siempre tiene la misma pila de llamadas de una entrada, en el mismo método en la misma dirección. Este método puede o no estar relacionado: usamos el VCL en nuestra aplicación. Mi apuesta, sin embargo, es que algo (posiblemente hace bastante tiempo) está corrompiendo la pila, y la dirección donde se bloquea es efectivamente aleatoria. Sin embargo, tenga en cuenta que ha sido la misma dirección en varias compilaciones, probablemente no sea realmente aleatoria.
Esto es lo que he intentado:
- tratando de reproducir de forma fiable en un momento determinado. No he encontrado nada que lo reproduzca todo el tiempo, y un par de cosas que ocasionalmente hacen, o no, sin motivo aparente. Estas no son acciones lo suficientemente 'estrechas' como para limitarlo a una sección particular de código. Puede estar relacionado con el tiempo, pero en el momento en que el IDE se rompe, otros hilos generalmente no hacen nada. No puedo descartar un problema de subprocesamiento, pero creo que es poco probable.
- Construyendo con declaraciones de depuración adicionales (información de depuración adicional, afirmaciones adicionales, etc.) Después de hacerlo, el bloqueo nunca se produce.
- Edificio con Codeguard activado. Después de hacerlo, el bloqueo nunca ocurre y Codeguard no muestra ningún error.
Mis preguntas:
1. ¿Cómo puedo encontrar qué código causó el accidente? ¿Cómo hago el equivalente a caminar de nuevo por la pila?
2. ¿Qué consejos generales tiene para encontrar la causa de este bloqueo?
estoy usando Embarcadero RAD Studio 2010 (el proyecto contiene sobre todo el código C++ Builder y pequeñas cantidades de Delphi.)
Editar: pensé que debería agregar lo que realmente causó esto. Hubo un hilo que llamó al ReadDirectoryChangesW
y luego, usando GetOverlappedResult
, esperó en un evento para continuar y hacer algo con los cambios.El evento también fue señalado para terminar el hilo después de configurar un indicador de estado. El problema era que cuando el hilo salía nunca llamaba al CancelIO
. Como resultado, Windows todavía realizaba un seguimiento de los cambios y probablemente seguía escribiendo en el búfer cuando el directorio cambiaba, aunque el búfer, la estructura solapada y el evento ya no existían (ni el contexto de subproceso en el que se crearon). Cuando se llamó CancelIO
, no hubo más accidentes.
No estoy familiarizado con CodeGaurd - ¿también presenta la pila de canarios y la validación? Lo pregunto porque estás mezclando C++ y Delphi, lo que significa que puedes estar mezclando convenciones de llamadas sin darte cuenta. Eso puede estropear muy rápidamente tu pila de forma que se manifiesta como un bloqueo aparentemente aleatorio en tu hilo principal con una pila de llamadas dañada. –
Codeguard rellena la porción no inicializada de la pila con un patrón de bytes. También (intenta) verificar cosas como acceder a la memoria liberada, sobrepasar la memoria asignada, etc. Conseguir una convención de llamadas incorrecta definitivamente causaría algo como esto, sí (¡y gracias por la sugerencia!) Pero si es así, no tengo idea de dónde : C++ Builder está diseñado para interoperar con el código Delphi y tendríamos que haber cometido un error en una declaración en alguna parte, y la mayoría son IDE o compiladores. Supongo que la pregunta clave es, ¿cómo podría encontrar un método incorrectamente declarado? –
No voy a poner esto como una respuesta porque es vago, pero es posible que desee probar un depurador diferente. Puedes dar, por ejemplo, Consejos WinDbg (o todo) para reconstruir la pila de llamadas real si se ha dañado o confundido. –