98 votes

Programme plante seulement la version build -- comment déboguer?

J'ai un "Chat de Schroedinger" type de problème ici -- mon programme (en fait de la suite de test pour mon programme, mais un programme d'ailleurs) est en panne, mais seulement lors de sa construction en mode release, et seulement lorsqu'il est lancé à partir de la ligne de commande. Par le biais de l'homme des cavernes de débogage (c'est à dire, méchant printf() messages dans tous les sens), j'ai déterminé la méthode de test où le code est en panne, mais malheureusement, la réelle crash semble se produire dans certains destructeur, depuis la dernière trace des messages je vois dans d'autres destructeurs qui exécuter proprement.

Lorsque je tente de l'exécuter ce programme à l'intérieur de Visual Studio, il ne plante pas. En va de même lors du lancement de WinDbg.exe. Le blocage se produit uniquement lors du lancement de la ligne de commande. Ce qui se passe sous Windows Vista, btw, et, malheureusement, je n'ai pas accès à une machine XP dès maintenant pour tester.

Il serait vraiment bien si je pouvais obtenir Windows pour imprimer une trace de la pile, ou quelque chose d' autre que de simplement terminer le programme comme si elle avait quitté proprement. Quelqu'un aurait-il des conseils sur comment je pourrais obtenir plus de renseignements utiles ici et nous espérons résoudre ce bug?

Edit: Le problème a effectivement été causé par un hors des limites d'un tableau, que je décrirai plus dans ce post. Merci à tous pour votre aide dans la recherche de ce problème!

135voto

James Curran Points 55356

Dans 100% des cas que j'ai vu ou entendu parler de, où un programme C ou C++ fonctionne très bien dans le débogueur, mais échoue lors de l'exécution à l'extérieur, la cause a été écrit après la fin d'une fonction locale de tableau. (Le débogueur met plus sur la pile, de sorte que vous êtes moins susceptibles de remplacer quelque chose d'important.)

58voto

David Dibben Points 7968

Lorsque j'ai rencontré des problèmes de ce genre auparavant, il a été généralement en raison de l'initialisation d'une variable. En mode debug, les variables et pointeurs sont initialisées à zéro automatiquement, mais en mode release, ils ne le font pas. Par conséquent, si vous avez un code comme ceci

int* p;
....
if (p == 0) { // do stuff }

En mode debug, le code dans le si n'est pas exécuté, mais en mode release, p contient une valeur non définie, ce qui est peu probable 0, donc le code est exécuté souvent provoquer un incident.

Je voudrais vérifier votre code pour les variables non initialisées. Cela peut également s'appliquer au contenu des tableaux.

30voto

Sebastian Points 3419

Pas de réponse jusqu'à présent, a essayé de donner un sérieux aperçu sur les techniques disponibles pour le débogage des applications à libération:

  1. Release et Debug de se comporter différemment pour de nombreuses raisons. Voici un excellent aperçu. Chacun de ces différences pourrait causer un bug dans la version Release qui n'existe pas dans la version Debug.

  2. La présence d'un débogueur peut modifier le comportement d'un programme, à la fois pour la release et debug. Voir cette réponse. En bref, au moins le Débogueur Visual Studio utilise le Débogage Tas automatiquement lorsqu'il est connecté à un programme. Vous pouvez activer le débogage tas en utilisant la variable d'environnement _NO_DEBUG_HEAP . Vous pouvez spécifier ce soit dans vos propriétés de l'ordinateur, ou dans les Paramètres du Projet dans Visual Studio. Que peut faire le crash reproductible avec le débogueur.

    Plus sur le débogage des tas de corruption.

  3. Si la solution précédente ne fonctionne pas, vous avez besoin pour attraper l'exception non gérée et joindre un post-mortem débogueur l'instance de la collision. Vous pouvez utiliser, par exemple, WinDbg pour cela, des détails sur la avaiable post-mortem des débogueurs et leur installation sur le site MSDN

  4. Vous pouvez améliorer votre code de gestion des exceptions et si ce est une application de production, vous devez:

    un. Installation d'un custom de résiliation à l'aide de gestionnaire de std::set_terminate

    Si vous souhaitez déboguer ce problème localement, vous pouvez exécuter une boucle sans fin à l'intérieur de la résiliation de gestionnaire et de sortie du texte à la console pour vous informer qu' std::terminate a été appelé. Ensuite attacher le débogueur et vérifier la pile des appels. Ou vous imprimer la trace de la pile comme décrit dans cette réponse.

    Dans une application de production, vous pourriez envoyer un rapport d'erreurs de retour à la maison, idéalement avec un petit vidage de la mémoire, qui permet d'analyser le problème, comme décrit ici.

    b. Utilisation de Microsoft gestion structurée des exceptions mécanisme qui vous permet d'attraper les exceptions matérielles et logicielles. Voir MSDN. Vous pourriez garde parties de votre code à l'aide de la SEH et d'utiliser la même approche que dans une) pour déboguer le problème. SEH donne plus d'informations sur l'exception qui s'est produite que vous pouvez utiliser lors de l'envoi d'un rapport d'erreur à partir d'une production de l'app.

16voto

morechilli Points 4889

Choses à regarder dehors pour:

Tableau des dépassements - le débogueur visual studio inserts de rembourrage qui peut cesser se bloque.

Course à conditions - avez-vous plusieurs threads concernés si une condition de course de nombreux ne se montre que lorsqu'une application est exécutée directement.

Liens - est votre communiqué de construire en tirant dans les bonnes bibliothèques.

Choses à essayer:

Minidump - vraiment facile à utiliser (il suffit de le rechercher dans msdn) vous donne plein de vidage sur incident pour chaque thread. Vous venez de charger la sortie dans visual studio et c'est comme si vous étiez le débogage au moment de l'accident.

13voto

Franci Penov Points 45358

Vous pouvez définir WinDbg comme votre débogueur post-mortem. Cela permettra de lancer le débogueur et le joindre à la procédure lorsque l'incident se produit. Pour installer WinDbg pour le post-mortem de débogage, utilisez l'option /I (remarque il est en majuscule):

windbg /I

Plus de détails ici.

Quant à la cause, il est le plus probablement une variable non initialisé comme les autres réponses suggèrent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X