/ MT y / MD construyen fallas, pero solo cuando el depurador no está conectado: ¿cómo depurar? [duplicar]

StackOverflow https://stackoverflow.com/questions/811951

Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Tengo una pequeña aplicación C ++ de un solo subproceso, compilada y enlazada con Visual Studio 2005, que usa boost (crc, program_options y tokenizer), un puñado de STL y una variedad de otros encabezados de sistema.

(Su propósito principal es leer un .csv y generar un .dat binario personalizado y un .h que declare las estructuras que " expliquen " el formato del .dat.)

La herramienta se bloquea (infracción de acceso en NULL) cuando se ejecuta fuera del depurador, solo en la versión. P.ej. presionar F5 no hace que la herramienta se bloquee, Ctrl-F5 lo hace. Cuando vuelvo a adjuntar el depurador, obtengo esta pila:

ntdll.dll!_RtlAllocateHeap@12()  + 0x26916 bytes    
csv2bin.exe!malloc(unsigned int size=0x00000014)  Line 163 + 0x63 bytes C
csv2bin.exe!operator new(unsigned int size=0x00000014)  Line 59 + 0x8 bytes C++
>csv2bin.exe!Record::addField(const char * string=0x0034aac8)  Line 62 + 0x7 bytes  C++
csv2bin.exe!main(int argc=0x00000007, char * * argv=0x00343998)  Line 253   C++
csv2bin.exe!__tmainCRTStartup()  Line 327 + 0x12 bytes  C

La línea en la que se está estrellando es una asignación de apariencia algo inocua:

pField = new NumberField(this, static_cast<NumberFieldInfo*>(pFieldInfo));

... No creo que haya llegado al constructor todavía, solo está asignando memoria antes de saltar al constructor. También ha ejecutado este código docenas de veces en el momento en que se bloquea, generalmente en una ubicación consistente (pero por lo demás no sospechosa).

El problema desaparece al compilar con / MTd o / MDd (tiempo de ejecución de depuración), y vuelve cuando se usa / MT o / MD.

El NULL se carga desde la pila, y puedo verlo en la vista de memoria. _RtlAllocateHeap @ 12 + 0x26916 bytes parece un desplazamiento enorme , como si se hubiera realizado un salto incorrecto.

He intentado _HAS_ITERATOR_DEBUGGING en una versión de depuración y eso no ha provocado nada sospechoso.

Al eliminar un HeapValidate al principio y al final de Record :: addField se muestra un montón de OK hasta que se bloquea.

Esto solía funcionar. No estoy completamente seguro de qué fue lo que cambió entre ahora y la última vez que compilamos la herramienta (probablemente años atrás, quizás bajo un VS más antiguo). Hemos probado una versión anterior de boost (1.36 vs 1.38).

Antes de volver a la investigación manual del código o enviarlo a PC-Lint y analizar su salida, ¿alguna sugerencia sobre cómo depurar esto de manera efectiva?

[Estaré encantado de actualizar la pregunta con más información, si solicita información en los comentarios.]

¿Fue útil?

Solución

Una pequeña diferencia conocida entre la ejecución con el depurador adjunto o no es el montón de depuración del sistema operativo (consulte también ¿Por qué mi código se ejecuta lentamente cuando tengo el debugger conectado ?). 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.

Una vez que desactivas el montón de depuración, deberías ver el mismo bloqueo incluso con el depurador adjunto.

Dicho esto, tenga en cuenta que las corrupciones de la memoria pueden ser difíciles de depurar, ya que a menudo la causa real de la corrupción (como un exceso de búfer) puede estar muy lejos de donde se ven los síntomas (el bloqueo).

Otros consejos

Application Verifier fue súper útil para resolver esto una vez que tuve _NO_DEBUG_HEAP = 1 en el entorno, vea la respuesta aceptada aquí: ¿Dónde se liberó la memoria por última vez?

Probablemente también vale la pena mencionar pageheap , que encontré al mirar el Verificador de aplicaciones. Parece que cubre un terreno similar.

(FYI, fue un desbordamiento de búfer de un carácter:

m_pEnumName = (char*)malloc(strlen(data) /* missing +1 here */);
strcpy(m_pEnumName, data);

... otro argumento ridículamente bueno para no usar strcpy directamente.)

El bloqueo dentro de new o malloc suele ser un indicio de que la estructura (interna) de la implementación de malloc se ha dañado. Esto ocurre la mayor parte del tiempo escribiendo una asignación anterior (desbordamiento de búfer). Luego, en la próxima llamada a new o malloc, la aplicación se bloquea porque la estructura interna ahora contiene datos no válidos.

Compruebe si puede sobrescribir cualquier espacio asignado previamente.

Si su aplicación es portátil, puede intentar compilarla en Linux y ejecutarla en Valgrind .

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