Pregunta

Estoy depurando una aplicación C ++ multiproceso (nativa) en Visual & nbsp; Studio & nbsp; 2008. En ocasiones aparentemente aleatorias, obtengo un "Windows ha desencadenado un punto de interrupción ..." error con una nota de que esto podría deberse a una corrupción en el montón. Estos errores no siempre bloquean la aplicación de inmediato, aunque es probable que se bloquee poco después.

El gran problema con estos errores es que aparecen solo después de que la corrupción realmente ha tenido lugar, lo que los hace muy difíciles de rastrear y depurar, especialmente en una aplicación multiproceso.

  • ¿Qué tipo de cosas pueden causar estos errores?

  • ¿Cómo los depuro?

Consejos, herramientas, métodos, luces ... son bienvenidos.

¿Fue útil?

Solución

Verificador de aplicaciones combinado con Herramientas de depuración para Windows es una configuración increíble. Puede obtener ambos como parte del Windows Driver Kit o el SDK de Windows más ligero . (Descubrí el verificador de aplicaciones al investigar un pregunta anterior sobre un problema de corrupción del montón .) He usado BoundsChecker e Insure ++ (mencionado en otras respuestas) en el pasado también, aunque me sorprendió cuánta funcionalidad había en Application Verifier.

Cerca eléctrica (también conocida como "efence"), dmalloc , valgrind , etc., vale la pena mencionarlos, pero la mayoría de estos son mucho más fáciles de ejecutar con * nix que Windows. Valgrind es ridículamente flexible: he depurado un gran software de servidor con muchos problemas de montón al usarlo.

Cuando todo lo demás falla, puede proporcionar a su propio operador global nuevas / eliminar y sobrecargas de malloc / calloc / realloc; cómo hacerlo variará un poco dependiendo del compilador y la plataforma, y ??esto será un poco inversión, pero puede dar sus frutos a largo plazo. La lista de características deseables debería resultar familiar de dmalloc y electricfence, y el libro sorprendentemente excelente Escribir código sólido :

  • valores centinela : permita un poco más de espacio antes y después de cada asignación, respetando el requisito de alineación máxima; se llena con números mágicos (ayuda a detectar desbordamientos y desbordamientos del búfer, y el puntero "salvaje" ocasional)
  • relleno de asignación : llene nuevas asignaciones con un valor mágico distinto de 0: Visual C ++ ya lo hará por usted en las compilaciones de depuración (ayuda a detectar el uso de variables no inicializadas)
  • relleno libre : llene la memoria liberada con un valor mágico distinto de 0, diseñado para desencadenar una falla predeterminada si se desreferencia en la mayoría de los casos (ayuda a atrapar punteros colgantes)
  • retrasado gratis : no devuelva la memoria liberada al montón por un tiempo, manténgala libre pero no disponible (ayuda a atrapar más punteros colgantes, atrapa el doble libre próximo)
  • tracking : a veces puede ser útil poder registrar dónde se realizó una asignación

Tenga en cuenta que en nuestro sistema local de elaboración casera (para un objetivo incrustado) mantenemos el seguimiento separado de la mayoría de las otras cosas, porque la sobrecarga del tiempo de ejecución es mucho mayor.


Si está interesado en más razones para sobrecargar estas funciones / operadores de asignación, consulte mi respuesta a " Cualquier razón para sobrecargar el operador global nuevo y eliminar? " ; Dejando de lado la descarada autopromoción, enumera otras técnicas que son útiles para rastrear los errores de corrupción del montón, así como otras herramientas aplicables.


Debido a que sigo encontrando mi propia respuesta aquí cuando busco valores alloc / free / fence que MS usa, aquí está otra respuesta que cubre Microsoft dbgheap valores de relleno .

Otros consejos

Puede detectar muchos problemas de corrupción del montón al habilitar Page Heap para su aplicación. Para hacer esto, debe usar gflags.exe que viene como parte de Herramientas de depuración para Windows

Ejecute Gflags.exe y en las opciones del archivo de imagen para su ejecutable, marque " Habilitar montón de página " opción.

Ahora reinicie su exe y adjúntelo a un depurador. Con Page Heap habilitado, la aplicación se abrirá en el depurador cada vez que se produzca algún daño de montón.

Para ralentizar las cosas y realizar muchas comprobaciones de tiempo de ejecución, intente agregar lo siguiente en la parte superior de su main () o equivalente en Microsoft Visual Studio C ++

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );
  

¿Qué tipo de cosas pueden causar estos errores?

Hacer cosas malas con memoria, p. escribir después del final de un búfer, o escribir en un búfer después de que se haya liberado nuevamente al montón.

  

¿Cómo los depuro?

Use un instrumento que agregue la verificación automática de límites a su ejecutable: es decir, valgrind en Unix, o una herramienta como BoundsChecker (Wikipedia sugiere también Purify and Insure ++) en Windows.

Tenga en cuenta que esto ralentizará su aplicación, por lo que pueden quedar inutilizables si la suya es una aplicación en tiempo real.

Otra posible ayuda / herramienta de depuración podría ser el HeapAgent de MicroQuill.

Un consejo rápido que obtuve de Detectando acceso a memoria liberada es esto:

  

Si desea localizar el error   rápidamente, sin revisar cada   declaración que accede a la memoria   bloque, puede configurar el puntero de memoria   a un valor no válido después de liberar el   bloque:

#ifdef _DEBUG // detect the access to freed memory
#undef free
#define free(p) _free_dbg(p, _NORMAL_BLOCK); *(int*)&p = 0x666;
#endif

La mejor herramienta que encontré útil y funcionó siempre es la revisión de código (con buenos revisores de código).

Aparte de la revisión de código, primero probaría Página Montón . Page Heap tarda unos segundos en configurarse y, con suerte, podría detectar su problema.

Si no tiene suerte con Page Heap, descargue Herramientas de depuración para Windows de Microsoft y aprenda a usar WinDbg. Lo sentimos, no podría darte ayuda más específica, pero depurar la corrupción del montón de subprocesos múltiples es más un arte que una ciencia. Google para " WinDbg heap corruption " y deberías encontrar muchos artículos sobre el tema.

También es posible que desee verificar si está vinculando con la biblioteca de tiempo de ejecución C dinámica o estática. Si sus archivos DLL se vinculan con la biblioteca de tiempo de ejecución C estática, entonces los archivos DLL tienen montones separados.

Por lo tanto, si creara un objeto en una DLL e intentara liberarlo en otra DLL, obtendría el mismo mensaje que está viendo arriba. Este problema se menciona en otra pregunta de desbordamiento de pila, Liberando memoria asignada en una DLL diferente .

¿Qué tipo de funciones de asignación está utilizando? Recientemente recibí un error similar al usar las funciones de asignación de estilo Heap *.

Resultó que estaba creando el montón por error con la opción HEAP_NO_SERIALIZE . Esto esencialmente hace que las funciones de Heap se ejecuten sin seguridad de subprocesos. Es una mejora del rendimiento si se usa correctamente, pero nunca se debe usar si está usando HeapAlloc en un programa de subprocesos múltiples [1]. Solo menciono esto porque su publicación menciona que tiene una aplicación multiproceso. Si está utilizando HEAP_NO_SERIALIZE en cualquier lugar, elimínelo y probablemente solucionará su problema.

[1] Hay ciertas situaciones en las que esto es legal, pero requiere que serialice las llamadas a Heap * y, por lo general, no es el caso de los programas multiproceso.

Si estos errores ocurren al azar, existe una alta probabilidad de que haya encontrado carreras de datos. Por favor, compruebe: ¿modifica punteros de memoria compartida de diferentes hilos? Intel Thread Checker puede ayudar a detectar tales problemas en un programa multiproceso.

Además de buscar herramientas, considere buscar un posible culpable. ¿Hay algún componente que esté utilizando, quizás no escrito por usted, que no haya sido diseñado y probado para ejecutarse en un entorno multiproceso? O simplemente uno que no sabe se ha ejecutado en dicho entorno.

La última vez que me sucedió, fue un paquete nativo que se había utilizado con éxito en trabajos por lotes durante años. Pero era la primera vez en esta compañía que se usaba desde un servicio web .NET (que es multiproceso). Eso fue todo: habían mentido acerca de que el código era seguro para subprocesos.

Puede usar macros VC CRT Heap-Check para _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF o _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_10.

Me gustaría agregar mi experiencia. En los últimos días, resolví una instancia de este error en mi aplicación. En mi caso particular, los errores en el código fueron:

  • Eliminar elementos de una colección STL mientras se repite (creo que hay indicadores de depuración en Visual Studio para detectar estas cosas; lo capté durante la revisión del código)
  • Este es más complejo, lo dividiré en pasos:
    • Desde un hilo nativo de C ++, vuelva a llamar al código administrado
    • En tierra gestionada, llame a Control.Invoke y disponga de un objeto gestionado que envuelva el objeto nativo al que pertenece la devolución de llamada.
    • Dado que el objeto sigue vivo dentro del hilo nativo (permanecerá bloqueado en la llamada de devolución de llamada hasta que Control.Invoke finalice). Debo aclarar que uso boost :: thread , así que uso una función miembro como función de hilo.
    • Solución : use Control.BeginInvoke (mi GUI está hecha con Winforms) en su lugar para que el hilo nativo pueda terminar antes de que el objeto sea destruido (el propósito de la devolución de llamada es precisamente notificando que el hilo terminó y el objeto puede ser destruido).

Tuve un problema similar, y apareció de manera bastante aleatoria. Quizás algo estaba dañado en los archivos de compilación, pero terminé arreglándolo limpiando el proyecto primero y luego reconstruyéndolo.

Entonces, además de las otras respuestas dadas:

¿Qué tipo de cosas pueden causar estos errores? Algo corrupto en el archivo de compilación.

¿Cómo los depuro? Limpieza del proyecto y reconstrucción. Si se soluciona, probablemente este sea el problema.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top