Application Verifier combinado con Debugging Tools for Windows es una configuración increíble. Puede obtener ambos como parte del Kit de controladores de Windows o el SDK de Windows más ligero . (Descubrí Application Verifier cuando investigé una pregunta anterior sobre un problema de corrupción del montón ). También he usado BoundsChecker e Insure ++ (mencionado en otras respuestas) en el pasado, aunque me sorprendió cuánta funcionalidad había en Application Verifier.
Cerca eléctrica (también conocida como "efence"), dmalloc , valgrindVale la pena mencionar , etc., 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 proporcionarle 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á una pequeña inversión. pero puede dar sus frutos a largo plazo. La lista de características deseables debería ser familiar por dmalloc y cerca eléctrica, y el libro sorprendentemente excelente Writing Solid Code :
- valores centinela : permiten un poco más de espacio antes y después de cada asignación, respetando el requisito de alineación máxima; llenar con números mágicos (ayuda a detectar desbordamientos y desbordamientos del búfer, y el puntero "salvaje" ocasional)
- alloc fill : 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 : rellene la memoria liberada con un valor mágico distinto de 0, diseñado para desencadenar una falla predeterminada si en la mayoría de los casos se desreferencia (ayuda a atrapar punteros colgantes)
- sin demora : no devuelva la memoria liberada al montón por un tiempo, manténgala libre pero no disponible (ayuda a capturar más punteros colgantes, captura la doble liberación próxima)
- seguimiento : poder registrar dónde se realizó una asignación a veces puede ser útil
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 "¿Alguna razón para sobrecargar al 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 de aloc / free / fence que usa MS, aquí hay otra respuesta que cubre los valores de relleno de dbgheap de Microsoft .
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 Debugging Tools For Windows
Ejecute Gflags.exe y en las opciones del archivo de imagen para su ejecutable, marque la opción "Habilitar montón de página".
Ahora reinicie su exe y adjúntelo a un depurador. Con Page Heap habilitado, la aplicación se dividirá en depurador cada vez que ocurra algún daño en el montón.
fuente
Para realmente 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 ++fuente
Un artículo muy relevante es la depuración de daños en el montón con Application Verifier y Debugdiag .
fuente
Hacer cosas malas con la memoria, por ejemplo, escribir después del final de un búfer, o escribir en un búfer después de que se haya liberado nuevamente en el montón.
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 estos retrasarán su aplicación, por lo que pueden ser inutilizables si la suya es una aplicación suave en tiempo real.
Otra posible ayuda / herramienta de depuración podría ser HeapAgent de MicroQuill.
fuente
Un consejo rápido que obtuve al detectar el acceso a la memoria liberada es este:
fuente
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 Page Heap . Page Heap tarda unos segundos en configurarse y, con suerte, podría determinar su problema.
Si no tiene suerte con Page Heap, descargue Debugging Tools 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 "corrupción de montón WinDbg" y debería encontrar muchos artículos sobre el tema.
fuente
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 .
fuente
¿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
HEAP_NO_SERIALIZE
opción. Esto esencialmente hace que las funciones de Heap se ejecuten sin seguridad de subprocesos. Es una mejora en el rendimiento si se usa correctamente, pero nunca se debe usar si está usando HeapAlloc en un programa multiproceso [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.
fuente
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.
fuente
Además de buscar herramientas, considere buscar un probable 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 conoces ha ejecutado en ese 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.
fuente
Puede usar macros VC CRT Heap-Check para _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF o _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .
fuente
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:
Control.Invoke
y disponga de un objeto gestionado que envuelva el objeto nativo al que pertenece la devolución de llamada.Control.Invoke
finalice). Debo aclarar que usoboost::thread
, por lo que uso una función miembro como la función de hilo.Control.BeginInvoke
(mi GUI se hace con Winforms) para que el hilo nativo pueda terminar antes de que el objeto sea destruido (el propósito de la devolución de llamada es notificar con precisión que el hilo terminó y el objeto puede ser destruido).fuente
Tuve un problema similar, y surgió al azar. 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.
fuente