Tengo un problema del tipo "Schroedinger's Cat" aquí: mi programa (en realidad, el conjunto de pruebas para mi programa, pero un programa de todos modos) se bloquea, pero solo cuando está integrado en el modo de lanzamiento, y solo cuando se inicia desde la línea de comandos . A través de la depuración del hombre de las cavernas (es decir, mensajes de printf () desagradables por todas partes), he determinado el método de prueba donde el código se bloquea, aunque desafortunadamente el bloqueo real parece ocurrir en algún destructor, ya que los últimos mensajes de seguimiento que veo están en otros destructores que se ejecutan limpiamente.
Cuando intento ejecutar este programa dentro de Visual Studio, no se bloquea. Lo mismo ocurre cuando se inicia desde WinDbg.exe. El bloqueo solo ocurre cuando se inicia desde la línea de comandos. Esto está sucediendo en Windows Vista, por cierto, y desafortunadamente no tengo acceso a una máquina XP en este momento para probar.
Sería muy bueno si pudiera hacer que Windows imprima un seguimiento de la pila, o algo más que simplemente terminar el programa como si hubiera salido limpiamente. ¿Alguien tiene algún consejo sobre cómo podría obtener información más significativa aquí y, con suerte, corregir este error?
Editar: El problema fue causado por una matriz fuera de límites, que describo más en esta publicación . ¡Gracias a todos por su ayuda para encontrar este problema!
Respuestas:
En el 100% de los casos que he visto o escuchado, donde un programa C o C ++ funciona bien en el depurador pero falla cuando se ejecuta afuera, la causa ha sido escribir más allá del final de una matriz local de función. (El depurador pone más en la pila, por lo que es menos probable que sobrescriba algo importante).
fuente
Cuando he encontrado problemas como este antes, generalmente se debe a la inicialización de variables. En el modo de depuración, las variables y los punteros se inicializan a cero automáticamente, pero en el modo de liberación no. Por lo tanto, si tiene un código como este
En el modo de depuración, el código en if no se ejecuta, pero en el modo de lanzamiento p contiene un valor indefinido, que es poco probable que sea 0, por lo que el código se ejecuta a menudo provocando un bloqueo.
Verificaría su código en busca de variables no inicializadas. Esto también puede aplicarse al contenido de las matrices.
fuente
Hasta ahora, ninguna respuesta ha intentado dar una descripción seria sobre las técnicas disponibles para depurar aplicaciones de lanzamiento:
Las compilaciones de lanzamiento y depuración se comportan de manera diferente por muchas razones. Aquí hay una excelente descripción general. Cada una de estas diferencias puede causar un error en la compilación de la versión que no existe en la compilación de depuración.
La presencia de un depurador también puede cambiar el comportamiento de un programa , tanto para versiones de liberación como de depuración. Vea esta respuesta. En resumen, al menos el depurador de Visual Studio usa el montón de depuración automáticamente cuando se adjunta a un programa. Puede desactivar el montón de depuración utilizando la variable de entorno _NO_DEBUG_HEAP. Puede especificar esto en las propiedades de su computadora o en la Configuración del proyecto en Visual Studio. Eso podría hacer que el bloqueo sea reproducible con el depurador adjunto.
Más información sobre la depuración de la corrupción del montón aquí.
Si la solución anterior no funciona, debe detectar la excepción no controlada y adjuntar un depurador post mortem en la instancia en la que se produce el bloqueo. Puede utilizar, por ejemplo, WinDbg para esto, detalles sobre los depuradores post-mortem disponibles y su instalación en MSDN
Puede mejorar su código de manejo de excepciones y si se trata de una aplicación de producción, debe:
a. Instale un controlador de terminación personalizado usando
std::set_terminate
Si desea depurar este problema localmente, puede ejecutar un bucle sin fin dentro del controlador de terminación y enviar un texto a la consola para notificarle que
std::terminate
ha sido llamado. Luego adjunte el depurador y verifique la pila de llamadas. O imprime el seguimiento de la pila como se describe en esta respuesta.En una aplicación de producción, es posible que desee enviar un informe de error a casa, idealmente junto con un pequeño volcado de memoria que le permita analizar el problema como se describe aquí.
si. Utilice el mecanismo estructurado de manejo de excepciones de Microsoft que le permite detectar excepciones tanto de hardware como de software. Consulte MSDN . Puede proteger partes de su código usando SEH y usar el mismo enfoque que en a) para depurar el problema. SEH brinda más información sobre la excepción que se produjo que podría utilizar al enviar un informe de error desde una aplicación de producción.
fuente
Cosas a tener en cuenta:
Desbordamientos de matriz: el depurador de Visual Studio inserta relleno que puede detener los bloqueos.
Condiciones de carrera: ¿tiene varios subprocesos involucrados? Si es así, una condición de carrera solo se muestra cuando una aplicación se ejecuta directamente.
Vinculación: ¿la compilación de su lanzamiento está incorporando las bibliotecas correctas?
Cosas para probar:
Minivolcado: realmente fácil de usar (solo búsquelo en msdn) le dará un volcado completo para cada hilo. Simplemente carga la salida en Visual Studio y es como si estuvieras depurando en el momento del bloqueo.
fuente
Puede configurar WinDbg como su depurador post mortem. Esto iniciará el depurador y lo adjuntará al proceso cuando se produzca el bloqueo. Para instalar WinDbg para la depuración post mortem, use la opción / I (tenga en cuenta que está en mayúscula ):
Más detalles aquí .
En cuanto a la causa, lo más probable es que sea una variable unitaria, como sugieren las otras respuestas.
fuente
Después de muchas horas de depuración, finalmente encontré la causa del problema, que de hecho fue causado por un desbordamiento del búfer, causó una diferencia de un solo byte:
Este es un error de poste de cerca (error de uno por uno) y lo solucionó:
Lo extraño fue que hice varias llamadas a _CrtCheckMemory () alrededor de varias partes de mi código, y siempre devolvieron 1. Pude encontrar la fuente del problema colocando "return false;" llamadas en el caso de prueba y, finalmente, determinar mediante prueba y error dónde estaba la falla.
Gracias a todos por sus comentarios. ¡Aprendí mucho sobre windbg.exe hoy! :)
fuente
A pesar de que ha creado su archivo ejecutable como versión de lanzamiento, aún puede generar archivos PDB (base de datos del programa) que le permitirán apilar el seguimiento y realizar una cantidad limitada de inspección de variables. En su configuración de compilación hay una opción para crear los archivos PDB. Encienda esto y vuelva a vincularlo. Luego, intente ejecutar primero desde el IDE para ver si se bloquea. Si es así, genial, ya está todo listo para ver las cosas. Si no es así, cuando se ejecuta desde la línea de comandos, puede hacer una de dos cosas:
Cuando se le solicite que señale los archivos PDB, busque para encontrarlos. Si los PDB se colocaron en la misma carpeta de salida que su EXE o DLL, probablemente se recogerán automáticamente.
Los PDB proporcionan un enlace a la fuente con suficiente información de símbolos para que sea posible ver rastros de pila, variables, etc. Puede inspeccionar los valores de forma normal, pero tenga en cuenta que puede obtener lecturas falsas, ya que el pase de optimización puede significar solo cosas aparecen en los registros o las cosas suceden en un orden diferente al esperado.
NB: estoy asumiendo un entorno Windows / Visual Studio aquí.
fuente
Los bloqueos como este casi siempre se deben a que un IDE generalmente establecerá el contenido de la variable no inicializada en ceros, nulos o algún otro valor 'sensible', mientras que cuando se ejecuta de forma nativa obtendrá cualquier basura aleatoria que el sistema recoja.
Por lo tanto, es casi seguro que su error es que está usando algo como si estuviera usando un puntero antes de que se haya inicializado correctamente y se esté saliendo con la suya en el IDE porque no apunta a ningún lugar peligroso, o el valor lo maneja su comprobación de errores, pero en el modo de lanzamiento hace algo desagradable.
fuente
Para tener un volcado de memoria que pueda analizar:
También debe consultar las herramientas en Herramientas de depuración para Windows . Puede supervisar la aplicación y ver todas las excepciones de primera oportunidad que existían antes de su excepción de segunda oportunidad.
Espero eso ayude...
fuente
Una excelente manera de depurar un error como este es habilitar optimizaciones para su compilación de depuración.
fuente
Una vez tuve un problema cuando la aplicación se comportaba de manera similar a la tuya. Resultó ser un desbordamiento de búfer desagradable en sprintf. Naturalmente, funcionó cuando se ejecutó con un depurador adjunto. Lo que hice fue instalar un filtro de excepción no controlado ( SetUnhandledExceptionFilter ) en el que simplemente infinitamente (usando WaitForSingleObject en un identificador falso con un valor de tiempo de espera de INFINITE).
Entonces podrías algo como:
Luego adjunté el depurador después de que el error se manifestó (el programa gui dejó de responder).
Entonces puede hacer un volcado y trabajar con él más tarde:
O depúrelo de inmediato. La forma más sencilla es rastrear dónde se ha guardado el contexto del procesador mediante la maquinaria de manejo de excepciones en tiempo de ejecución:
El comando buscará el espacio de direcciones de la pila para los registros de CONTEXTO siempre que la duración de la búsqueda. Normalmente uso algo como 'l? 10000' . Tenga en cuenta que no utilice números inusualmente grandes, ya que el registro que busca suele estar cerca del marco del filtro de excepción sin mano. 1003f es la combinación de banderas (creo que corresponde a CONTEXT_FULL) que se usa para capturar el estado del procesador. Su búsqueda sería similar a esto:
Una vez que obtenga los resultados, use la dirección en el comando cxr:
Esto lo llevará a este nuevo CONTEXTO, exactamente en el momento del bloqueo (obtendrá exactamente el seguimiento de la pila en el momento en que se bloqueó la aplicación). Además, use:
para averiguar exactamente qué excepción se había producido.
Espero eso ayude.
fuente
A veces esto sucede porque ha envuelto una operación importante dentro de la macro "afirmar". Como sabrá, "assert" evalúa expresiones solo en modo de depuración.
fuente
Con respecto a sus problemas para obtener información de diagnóstico, ¿ha intentado utilizar adplus.vbs como alternativa a WinDbg.exe? Para adjuntar a un proceso en ejecución, use
O para iniciar la aplicación en caso de que el bloqueo se produzca rápidamente:
Puede encontrar información completa sobre adplus.vbs en: http://support.microsoft.com/kb/286350
fuente
Ntdll.dll con depurador adjunto
Una pequeña diferencia conocida entre iniciar un programa desde el IDE o WinDbg en lugar de iniciarlo desde la línea de comandos / escritorio es que cuando se inicia con un depurador adjunto (es decir, IDE o WinDbg), ntdll.dll usa una implementación de montón diferente que realiza una pequeña validación en la asignación / liberación de memoria.
Puede leer información relevante en el punto de interrupción inesperado del usuario en ntdll.dll . Una herramienta que podría ayudarlo a identificar el problema es PageHeap.exe .
Análisis de colisiones
No escribió cuál es el "bloqueo" que está experimentando. Una vez que el programa se bloquea y le ofrece enviar la información del error a Microsoft, debería poder hacer clic en la información técnica y verificar al menos el código de excepción, y con algo de esfuerzo puede incluso realizar un análisis post-mortem (ver Heisenbug : El programa WinApi se bloquea en algunas computadoras) para obtener instrucciones)
fuente
Vista SP1 en realidad tiene un generador de volcado por caída realmente agradable integrado en el sistema. Desafortunadamente, ¡no está activado de forma predeterminada!
Vea este artículo: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx
El beneficio de este enfoque es que no es necesario instalar ningún software adicional en el sistema afectado. ¡Agárralo y rómpelo, bebé!
fuente
Según mi experiencia, la mayoría son problemas de corrupción de memoria.
Por ejemplo :
es muy posible que sea normal en modo de depuración cuando se ejecuta el código.
Pero en el lanzamiento, eso sería / podría ser un accidente.
Para mí, hurgar donde la memoria está fuera de límites es demasiado laborioso.
Usar algunas herramientas como Visual Leak Detector (Windows) o valgrind (Linux) es una elección más inteligente.
fuente
He visto muchas respuestas correctas. Sin embargo, no hay ninguno que me haya ayudado. En mi caso, hubo un uso incorrecto de las instrucciones SSE con la memoria no alineada . Eche un vistazo a su biblioteca matemática (si usa una) e intente deshabilitar el soporte SIMD, recompile y reproduzca el bloqueo.
Ejemplo:
Un proyecto incluye mathfu y usa las clases con el vector STL: std :: vector <mathfu :: vec2> . Tal uso probablemente causará un bloqueo en el momento de la construcción del elemento mathfu :: vec2 ya que el asignador predeterminado de STL no garantiza la alineación requerida de 16 bytes. En este caso, para probar la idea, se puede definir
#define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1
antes de cada inclusión del mathfu , recompilar en la configuración de Release y verificar nuevamente.Las configuraciones Debug y RelWithDebInfo funcionaron bien para mi proyecto, pero no para el Release . La razón detrás de este comportamiento es probablemente porque el depurador procesa las solicitudes de asignación / desasignación y realiza una contabilidad de memoria para verificar y verificar los accesos a la memoria.
Experimenté la situación en entornos de Visual Studio 2015 y 2017.
fuente
Algo parecido me pasó una vez con GCC. Resultó ser una optimización demasiado agresiva que se habilitó solo al crear la versión final y no durante el proceso de desarrollo.
Bueno, a decir verdad, fue culpa mía, no de gcc, ya que no noté que mi código se basaba en el hecho de que esa optimización en particular no se habría realizado.
Me tomó mucho tiempo rastrearlo y solo llegué a él porque pregunté en un grupo de noticias y alguien me hizo pensar en ello. Entonces, permítame devolverle el favor en caso de que esto también le esté sucediendo a usted.
fuente
Encontré este artículo útil para su escenario. ISTR las opciones del compilador estaban un poco desactualizadas. Mire alrededor de las opciones de su proyecto de Visual Studio para ver cómo generar archivos pdb para su versión de lanzamiento, etc.
fuente
Es sospechoso que suceda fuera del depurador y no dentro; ejecutar en el depurador normalmente no cambia el comportamiento de la aplicación. Verificaría las diferencias de entorno entre la consola y el IDE. Además, obviamente, compile la versión sin optimizaciones y con información de depuración, y vea si eso afecta el comportamiento. Finalmente, consulte las herramientas de depuración post-mortem que otras personas han sugerido aquí, por lo general, puede obtener alguna pista de ellas.
fuente
La depuración de versiones de versiones puede ser una molestia debido a que las optimizaciones cambian el orden en el que parecen ejecutarse las líneas de su código. ¡Realmente puede resultar confuso!
Una técnica para al menos reducir el problema es usar MessageBox () para mostrar declaraciones rápidas que indiquen a qué parte del programa ha llegado su código ("Iniciando Foo ()", "Iniciando Foo2 ()"); comience a colocarlos en la parte superior de las funciones en el área de su código que sospecha (¿qué estaba haciendo en el momento en que falló?). Cuando pueda saber qué función, cambie los cuadros de mensaje a bloques de código o incluso a líneas individuales dentro de esa función hasta que la reduzca a unas pocas líneas. Luego, puede comenzar a imprimir el valor de las variables para ver en qué estado se encuentran al momento de fallar.
fuente
Intente usar _CrtCheckMemory () para ver en qué estado se encuentra la memoria asignada. Si todo va bien, _CrtCheckMemory devuelve VERDADERO , de lo contrario FALSO .
fuente
Puede ejecutar su software con las banderas globales habilitadas (busque en Herramientas de depuración para Windows). Muy a menudo ayudará a resolver el problema.
fuente
Haga que su programa genere un mini volcado cuando ocurra la excepción, luego ábralo en un depurador (por ejemplo, en WinDbg). Las funciones clave a tener en cuenta: MiniDumpWriteDump, SetUnhandledExceptionFilter
fuente
Aquí hay un caso que tuve que alguien podría encontrar instructivo. Solo se bloqueó en el lanzamiento en Qt Creator, no en la depuración. Estaba usando archivos .ini (ya que prefiero las aplicaciones que se pueden copiar a otras unidades, frente a las que pierden su configuración si el Registro se corrompe). Esto se aplica a cualquier aplicación que almacene su configuración en el árbol del directorio de aplicaciones. Si las compilaciones de depuración y liberación se encuentran en directorios diferentes, también puede tener una configuración diferente entre ellos. Preferí registrarme en uno que no estaba marcado en el otro. Resultó ser la causa de mi accidente. Menos mal que lo encontré.
Odio decirlo, pero solo diagnostiqué el bloqueo en MS Visual Studio Community Edition; después de instalar VS, dejar que mi aplicación se bloquee en Qt Creator y elegir abrirla en el depurador de Visual Studio . Si bien mi aplicación Qt no tenía información de símbolos, resulta que las bibliotecas Qt tenían algunos. Me llevó a la línea ofensiva; ya que pude ver qué método se estaba llamando. (Aún así, creo que Qt es un marco LGPL conveniente, poderoso y multiplataforma).
fuente
Tuve este error y vs se bloqueó incluso cuando intentaba! Clean! mi proyecto. Así que eliminé los archivos obj manualmente del directorio Release, y después de eso, se construyó bien.
fuente
Estoy de acuerdo con Rolf. Debido a que la reproducibilidad es tan importante, no debería tener un modo sin depuración. Todas sus compilaciones deberían poder depurarse. Tener dos objetivos para depurar más del doble su carga de depuración. Simplemente envíe la versión en "modo de depuración", a menos que no se pueda utilizar. En cuyo caso, hágalo utilizable.
fuente