Le build / MT e / MD si arrestano in modo anomalo, ma solo quando il debugger non è collegato: come eseguire il debug? [duplicare]

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

Domanda

    

Questa domanda ha già una risposta qui:

         

Ho una piccola applicazione C ++ a thread singolo, compilata e collegata usando Visual Studio 2005, che utilizza boost (crc, program_options e tokenizer), un'infarinatura di STL e varie intestazioni di sistema assortite.

(Il suo scopo principale è leggere in un .csv e generare un .dat binario personalizzato e un .h accoppiato che dichiari strutture che "spiegano" il formato del .dat.)

Lo strumento si arresta in modo anomalo (violazione di accesso su NULL) quando eseguito all'esterno del debugger, solo in versione. Per esempio. premendo F5 non si verifica l'arresto anomalo dello strumento, Ctrl-F5 lo fa. Quando ricollego il debugger, ottengo questo stack:

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 linea su cui si sta schiantando è una allocazione dall'aspetto un po 'innocua:

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

... Non credo che abbia ancora raggiunto il costruttore, sta solo allocando la memoria prima di saltare al costruttore. Ha anche eseguito questo codice dozzine di volte quando si blocca, di solito in una posizione coerente (ma per il resto non sospetta).

Il problema scompare durante la compilazione con / MTd o / MDd (debug runtime) e ritorna quando si utilizza / MT o / MD.

Il NULL viene caricato dallo stack e posso vederlo nella vista memoria. _RtlAllocateHeap @ 12 + 0x26916 byte sembra un enorme offset, come se fosse stato effettuato un salto errato.

Ho provato _HAS_ITERATOR_DEBUGGING in una build di debug e che non ha sollevato nulla di sospetto.

Eliminazione di un HeapValidate all'inizio e alla fine di Record :: addField mostra un heap OK fino a quando si arresta in modo anomalo.

Questo funzionava: non sono del tutto sicuro di cosa sia cambiato tra ora e l'ultima volta che abbiamo compilato lo strumento (probabilmente anni fa, forse sotto un vecchio VS). Abbiamo provato una versione precedente di boost (1,36 vs 1,38).

Prima di tornare all'indagine manuale del codice o di inviarlo a PC-Lint e analizzarne l'output, qualche suggerimento su come eseguire il debug in modo efficace?

[Sarò felice di aggiornare la domanda con maggiori informazioni, se richiedi informazioni nei commenti.]

È stato utile?

Soluzione

Una piccola differenza nota tra l'esecuzione con il debugger collegato o meno è l'heap di debug del sistema operativo (vedi anche Perché il mio codice gira lentamente quando ho il debugger collegato ?). È possibile disattivare l'heap di debug utilizzando la variabile di ambiente _NO_DEBUG_HEAP. Puoi specificarlo nelle proprietà del tuo computer o nelle Impostazioni del progetto in Visual Studio.

Dopo aver disattivato l'heap di debug, dovresti vedere lo stesso crash anche con il debugger collegato.

Detto questo, tieni presente che i danneggiamenti della memoria possono essere difficili da debug, poiché spesso la vera causa della corruzione (come un sovraccarico del buffer) potrebbe essere molto lontana da dove vedi i sintomi (il crash).

Altri suggerimenti

Verificatore applicazioni è stato super utile per risolvere questo problema una volta che avevo _NO_DEBUG_HEAP = 1 in ambiente, vedi la risposta accettata qui: Trova dove è stata liberata l'ultima memoria?

Probabilmente vale anche la pena menzionare pageheap , che ho trovato guardando Application Verifier. Sembra che copra un terreno simile.

(A proposito, era un buffer overflow di un carattere:

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

... ancora un altro argomento ridicolmente buono per non usare strcpy direttamente.)

Il crash all'interno di new o malloc di solito è un suggerimento che la struttura (interna) dell'implementazione di malloc è stata corrotta. Questo è il più delle volte fatto scrivendo oltre un'allocazione precedente (buffer overflow). Quindi alla chiamata successiva a new o malloc l'app si arresta in modo anomalo poiché la struttura interna ora contiene dati non validi.

Verifica se è possibile sovrascrivere qualsiasi spazio allocato precedente.

Se l'applicazione è portatile, puoi provare a crearla su Linux ed eseguirla in Valgrind .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top