Les générations / MT et / MD se bloquent, mais uniquement lorsque le débogueur n'est pas attaché: comment déboguer? [dupliquer]

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

Question

    

Cette question a déjà une réponse ici:

         

J'ai une petite application C ++ à un seul thread, compilée et liée à l'aide de Visual Studio 2005, qui utilise boost (crc, options_programmes et tokenizer), une poignée de fichiers STL et divers en-têtes système.

(Son objectif principal est de lire un fichier .csv et de générer un fichier .dat binaire personnalisé et un fichier .h déclarant des structures qui "expliquent" le format du fichier .dat.)

L'outil se bloque (violation d'accès sur NULL) lorsqu'il est exécuté en dehors du débogueur, uniquement en version. Par exemple. appuyer sur F5 ne provoque pas le blocage de l'outil, contrairement à Ctrl-F5. Lorsque je rattache le débogueur, je reçois cette pile:

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 ligne sur laquelle elle se bloque est une allocation quelque peu anodine:

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

... Je ne crois pas qu'il ait atteint le constructeur, il s'agit simplement d'allouer de la mémoire avant de passer au constructeur. Il a également exécuté ce code des dizaines de fois au moment où il se bloque, généralement dans un emplacement cohérent (mais non suspect).

Le problème disparaît lors de la compilation avec / MTd ou / MDd (exécution du débogage) et revient lors de l'utilisation de / MT ou / MD.

La valeur NULL est chargée à partir de la pile et je peux la voir en mode mémoire. _RtlAllocateHeap @ 12 + 0x26916 octets semble être un énorme décalage, comme si un saut incorrect avait été effectué.

J'ai essayé _HAS_ITERATOR_DEBUGGING dans une version de débogage et cela n'a rien révélé de suspect.

Le fait de déposer HeapValidate au début et à la fin de Record :: addField affiche un tas OK jusqu'au moment où il se bloque.

Cela fonctionnait auparavant - je ne suis pas tout à fait sûr de ce qui a changé entre maintenant et la dernière fois que nous avons compilé l'outil (il y a probablement des années, peut-être sous un ancien VS). Nous avons essayé une version plus ancienne de boost (1.36 vs 1.38).

Avant de revenir à l’investigation manuelle du code ou de l’envoyer à PC-Lint et d’en extraire le contenu, vous avez des suggestions sur la façon de déboguer efficacement?

[Je me ferai un plaisir de mettre à jour la question avec plus d'informations, si vous demandez des informations dans les commentaires.]

Était-ce utile?

La solution

Le tas de débogage du système d'exploitation (voir aussi Pourquoi mon code s'exécute-t-il lentement lorsque j'ai le débogueur attaché ?). Vous pouvez désactiver le segment de débogage à l'aide de la variable d'environnement _NO_DEBUG_HEAP. Vous pouvez le spécifier dans les propriétés de votre ordinateur ou dans les paramètres du projet de Visual Studio.

Une fois le tas de débogage désactivé, vous devriez voir le même crash, même si le débogueur est connecté.

Cela dit, sachez que les corruptions de mémoire peuvent être difficiles à déboguer, car souvent la cause réelle de la corruption (comme un dépassement de tampon) peut être très éloignée de la source des symptômes (le crash).

Autres conseils

Application Verifier était super utile pour résoudre ceci une fois que j’avais _NO_DEBUG_HEAP = 1 dans l’environnement, voir la réponse acceptée ici: Recherche de la dernière libération de la mémoire?

Il convient également de mentionner pageheap , que j'ai trouvé en consultant Application Verifier. On dirait qu'il couvre un terrain similaire.

(Pour info, il s’agissait d’un débordement de mémoire tampon d’un caractère:

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

... encore un argument ridiculement bon pour ne pas utiliser strcpy directement.)

Un crash dans new ou malloc indique généralement que la structure (interne) de la mise en œuvre de malloc a été corrompue. Cela se fait la plupart du temps en écrivant au-delà d'une allocation précédente (débordement de mémoire tampon). Ensuite, lors du prochain appel à new ou malloc, l'application se bloque car la structure interne contient désormais des données non valides.

Vérifiez si vous pouvez écraser tout espace alloué précédemment.

Si votre application est portable, vous pouvez essayer de la construire sous Linux et de l'exécuter sous Valgrind .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top