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

j'ai un problème de type" Chat de Schroedinger " ici -- mon programme (en fait la suite de test pour mon programme, mais un programme néanmoins) est en panne, mais seulement lorsqu'il est construit en mode release, et seulement lorsqu'il est lancé à partir de la ligne de commande. Grâce au débogage de caveman (c'est-à-dire, des messages de printf () méchants partout), j'ai déterminé la méthode de test où le code s'écrase, bien que malheureusement le crash réel semble se produire dans un destructeur, puisque les derniers messages de trace que je vois sont en d'autres destructeurs qui exécuter proprement.

quand je tente d'exécuter ce programme à L'intérieur de Visual Studio, il ne se bloque pas. Il en va de même pour la mise à l'eau à partir de WinDbg.EXE. Le blocage se produit uniquement lors du lancement de la ligne de commande. Cela se passe sous Windows Vista, btw, et malheureusement je n'ai pas accès à une machine XP en ce moment pour tester sur.

ce serait vraiment bien si je pouvais avoir Windows pour imprimer une trace de pile, ou quelque chose autre que simplement mettre fin au programme comme si elle avait quitté proprement. Est-ce que quelqu'un a des conseils sur la façon dont je pourrais obtenir des informations plus significatives ici et j'espère corriger ce bug?

Edit: le problème a en effet été causé par un tableau hors-limites, que je décris plus dans ce post . Merci à tous pour votre aide dans la recherche de ce problème!

80
demandé sur Community 2008-10-09 11:18:42

27 réponses

dans 100% des cas où j'ai vu ou entendu parler, où un programme C ou c++ fonctionne très bien dans le débogueur mais échoue lorsqu'il est exécuté à l'extérieur, la cause a été écrite après la fin d'un tableau local de fonction. (Le débogueur met plus sur la pile, donc vous êtes moins susceptible d'écraser quelque chose d'important.)

109
répondu James Curran 2008-10-09 07:41:26

quand j'ai rencontré des problèmes comme celui-ci avant qu'il ait été généralement due à l'initialisation variable. En mode debug, les variables et les pointeurs sont initialisés automatiquement à zéro, mais pas en mode release. Par conséquent, si vous avez le 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, qui ne sera probablement pas 0, de sorte que le code est souvent exécuté provoquant un crash.

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

46
répondu David Dibben 2008-10-09 07:24:56

choses à surveiller:

overruns de tableau-le débogueur visual studio insère un rembourrage qui peut arrêter les accidents.

conditions de course-avez-vous plusieurs threads impliqués si donc une condition de course beaucoup apparaissent seulement quand une application est exécutée directement.

lien-est votre construction de version tirant dans les bibliothèques correctes.

choses à essayer:

Minidump-really facile à utiliser (cherchez simplement dans msdn) vous donnera un dump crash complet pour chaque thread. Vous chargez simplement la sortie dans visual studio et c'est comme si vous déboguiez au moment du crash.

15
répondu morechilli 2008-10-09 08:15:37

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

  1. les constructions de Release et de Debug se comportent différemment pour de nombreuses raisons. voici un excellent aperçu. chacune de ces différences pourrait causer un bogue dans la compilation de la version qui n'existe pas dans la compilation de débogage.

  2. la présence d'un débogueur peut changer le comportement d'un programme aussi , à la fois pour les compilations release et debug. voir cette réponse. en bref, au moins le débogueur Visual Studio utilise le tas de débogueurs automatiquement lorsqu'il est attaché à un programme. Vous pouvez désactiver le tas de débogage en utilisant la variable d'environnement _NO_DEBUG_HEAP . Vous pouvez le spécifier soit dans les propriétés de votre ordinateur, soit dans les paramètres du projet dans Visual Studio. Que peut faire le crash reproductible avec le débogueur.

    pour en savoir plus sur la corruption de tas de débogage, Cliquez ici.

  3. si la solution précédente ne fonctionne pas, vous devez saisir l'exception non manipulée et attacher un débogueur post-mortem l'instance où le crash se produit. Vous pouvez utiliser par exemple WinDbg pour cela, détails sur les débogueurs post-mortem disponibles et leur installation chez MSDN

  4. vous pouvez améliorer votre code de traitement des exceptions et s'il s'agit d'une application de production, vous devez:

    A. installer un gestionnaire de terminaison personnalisé en utilisant std::set_terminate

    si vous voulez déboguer ce problème localement, vous pouvez lancer une boucle sans fin à l'intérieur du gestionnaire de terminaison et afficher du texte sur la console pour vous informer que std::terminate a été appelé. Ensuite, attachez le débogueur et vérifiez la pile d'appels. ou vous imprimez la trace de pile comme décrit dans cette réponse.

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

    B. utiliser le traitement d'exception structuré de Microsoft mécanisme qui vous permet d'attraper à la fois le matériel et le logiciel exceptions. voir MSDN . Vous pouvez garder des parties de votre code en utilisant SEH et utiliser la même approche que dans a) pour déboguer le problème. SEH donne plus d'informations sur l'exception qui s'est produite que vous pourriez utiliser lors de l'envoi d'un rapport d'erreur à partir d'une application de production.

15
répondu Sebastian 2017-05-23 12:18:34

vous pouvez définir WinDbg comme votre débogueur post mortem. Cela lancera le débogueur et le fixera au processus lorsque le crash se produit. Pour installer WinDbg pour le débogage postmortem, utilisez l'option /I (notez qu'il s'agit de capitalisé ):

windbg /I

plus de détails ici .

quant à la cause, c'est très probablement une variable unitialisée comme le suggèrent les autres réponses.

12
répondu Franci Penov 2008-10-09 07:33:04

après de nombreuses heures de débogage, j'ai finalement trouvé la cause du problème, qui était en effet causé par un débordement de tampon, causé une seule différence d'octet:

char *end = static_cast<char*>(attr->data) + attr->dataSize;

il s'agit d'une erreur de fencepost (erreur "off-by-one") qui a été corrigée par:

char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;

ce qui est bizarre, c'est que j'ai passé plusieurs appels à _CrtCheckMemory() autour de différentes parties de mon code, et ils m'ont toujours renvoyé 1. J'ai pu trouver la source du problème en plaçant "return false;" appels dans le cas du test, et puis finalement se déterminer par essais et erreurs où la faute a été.

merci à tous pour vos commentaires -- j'ai beaucoup appris sur windbg.exe aujourd'hui! :)

8
répondu Nik Reiman 2008-10-09 16:04:55

même si vous avez construit votre exe comme une version un, vous pouvez toujours générer des fichiers PDB (base de données de programme) qui vous permettront d'empiler trace, et faire une quantité limitée d'inspection variable. Dans vos paramètres de construction, il y a une option pour créer les fichiers PDB. Activez cette fonction et de rétablir le lien. Alors essayez de fuir L'IDE d'abord pour voir si vous obtenez le crash. Si c'est le cas, alors génial - vous êtes prêt à regarder les choses. Si non, alors en fuyant la ligne de commande vous pouvez faire l'une des deux choses:

  1. lancer EXE, et avant le crash faire une attache au processus (menu Outils sur Visual Studio).
  2. Après le crash, sélectionnez l'option pour lancer le débogueur.

lorsqu'on leur demande de pointer vers les fichiers PDB, parcourez-les pour les trouver. Si les PDB ont été placés dans le même dossier de sortie que votre EXE ou DLL, ils seront probablement ramassés automatiquement.

L'APB est de fournir un lien vers la source avec assez de informations sur les symboles pour permettre de voir les traces de stack, les variables, etc. Vous pouvez inspecter les valeurs comme d'habitude, mais sachez que vous pouvez obtenir de fausses lectures car le passage à l'optimisation peut signifier que les choses n'apparaissent que dans les registres, ou que les choses se produisent dans un ordre différent de ce que vous attendez.

NB: je suppose un environnement Windows/Visual Studio ici.

7
répondu Greg Whitfield 2008-10-09 07:51:03

afin d'avoir un crash dump que vous pouvez analyser:

  1. générer des fichiers pdb pour votre code.
  2. vous rebasez pour avoir votre exe et dlls chargés dans la même adresse.
  3. activer le débogueur post mortem tel que Dr. Watson
  4. Vérifiez l'adresse crash failures en utilisant un outil tel que crash finder .

Vous devrait également vérifier les outils dans outils de débogage pour windows . Vous pouvez surveiller l'application et voir toutes les exceptions de la première chance qui ont précédé votre exception de la deuxième chance.

J'espère que ça aidera...

3
répondu Yuval Peled 2008-10-09 07:38:51

Incidents de ce genre sont presque toujours causés en raison d'un IDE est généralement réglé le contenu de la variable non initialisée à zéros, null, ou quelque autre "raisonnable" de la valeur, alors que lors de l'exécution en mode natif, vous obtiendrez quelque soit aléatoire ordures que le système de ramasse.

votre erreur est donc presque certainement que vous utilisez quelque chose comme vous utilisez un pointeur avant qu'il ait été correctement initialisé et vous vous en sortez avec lui dans L'IDE parce qu'il ne pointez n'importe où dangereux - ou la valeur est gérée par votre vérification d'erreur - mais en mode de libération il fait quelque chose de méchant.

2
répondu Cruachan 2008-10-09 07:29:31

une fois, j'ai eu un problème quand app s'est comportée de la même façon que la vôtre. Il s'est avéré qu'il y avait une mauvaise surcharge de tampon dans sprintf. Naturellement, cela a fonctionné quand le débogueur était attaché. Ce que j'ai fait, était d'installer un filtre d'exception non manipulé ( SetUnhandledExceptionFilter ) dans lequel j'ai tout simplement bloqué à l'infini (en utilisant WaitForSingleObject sur une poignée bidon avec une valeur de timeout D'infini).

donc vous pourriez quelque chose le long les lignes de:

long __stdcall MyFilter(EXCEPTION_POINTERS *)
{
    HANDLE hEvt=::CreateEventW(0,1,0,0);
    if(hEvt)
    {
        if(WAIT_FAILED==::WaitForSingleObject(hEvt, INFINITE))
        {
            //log failure
        }
    }

}
// somewhere in your wmain/WinMain:
SetUnhandledExceptionFilter(MyFilter);

j'ai alors attaché le débogueur après que le bogue se soit manifesté (le programme gui a cessé de répondre).

alors vous pouvez soit prendre une décharge et travailler avec elle plus tard:

.dump / ma path_to_dump_file

ou déboguez tout de suite. La manière la plus simple est de suivre où le contexte du processeur a été sauvegardé par la machine de gestion des exceptions d'exécution:

S-D esp Gamme 1003f
La commande

recherchera l'espace d'adresse de la pile pour le(S) enregistrement (s) de contexte pourvu que la durée de la recherche. J'utilise habituellement quelque chose comme 'l?10000' . Remarque, n'utilisez pas de grands nombres non habituels car l'enregistrement que vous recherchez est habituellement proche du cadre du filtre d'exception. 1003f est la combinaison de drapeaux (je crois qu'elle correspond à CONTEXT_FULL) utilisée pour capturer l'état du processeur. Votre recherche ressemblerait à ceci:

0: 000 > s-d esp L1000 1003f

0012c160 0001003f 00000000 00000000 00000000?...............

une fois les résultats obtenus, utilisez l'adresse de la commande cxr:

.cxr 0012c160

cela vous mènera à ce nouveau contexte, exactement au moment du crash (vous obtiendrez exactement le stack trace au moment où votre application s'est écrasée). En outre, utiliser:

.exr -1

pour savoir exactement quelle exception s'était produite.

J'espère que ça aidera.

2
répondu deemok 2008-10-09 08:25:20

parfois cela se produit parce que vous avez enveloppé opération importante à l'intérieur de "affirmer" macro. Comme vous le savez peut-être, "assert" n'évalue les expressions que sur le mode de débogage.

2
répondu Mohamad mehdi Kharatizadeh 2014-05-28 09:28:37

en ce qui concerne vos problèmes d'obtenir des informations de diagnostic, avez-vous essayé d'utiliser adplus.vbs comme alternative au WinDbg.exe? Pour joindre à un processus en cours d'exécution, utilisez

adplus.vbs -crash -p <process_id>

ou pour démarrer l'application dans le cas où le crash se produit rapidement:

adplus.vbs -crash -sc your_app.exe

informations complètes sur adplus.vbs peut être trouvé à: http://support.microsoft.com/kb/286350

1
répondu DocMax 2008-10-09 07:38:25

Ntdll.dll avec débogueur attaché

une petite différence connue entre le lancement d'un programme à partir de L'IDE ou WinDbg par opposition au lancement à partir de la ligne de commande / bureau est que lors du lancement avec un débogueur attaché (i.e. IDE ou WinDbg) ntdll.dll utilise une implémentation tas différente qui effectue une petite validation sur l'allocation/libération de la mémoire.

vous pouvez lire quelques informations pertinentes dans utilisateur inattendu point de rupture à ntdll.dll . Un outil qui pourrait vous aider à identifier le problème est PageHeap.exe .

analyse de la panne

vous n'avez pas écrit ce qui est le" crash " que vous expérimentez. Une fois que le programme se bloque et vous offre d'envoyer les informations d'erreur à Microsoft, vous devriez être en mesure de cliquer sur les informations techniques et de vérifier au moins le code d'exception, et avec un certain effort, vous pouvez même effectuer une analyse post mortem (voir Heisenbug: le programme WinApi s'écrase sur certains ordinateurs) pour les instructions)

1
répondu Suma 2017-05-23 12:10:54

Vista SP1 a en fait un très beau générateur de crash dump intégré dans le système. Malheureusement, il n'est pas activé par défaut!

voir cet article: http://msdn.microsoft.com/en-us/library/bb787181 (VS.85).aspx

L'avantage de cette approche est qu'aucun logiciel supplémentaire ne doit être installé sur le système affecté. Poignée et déchirer, bébé!

1
répondu 2009-08-19 16:16:40

comme mon expérience, qui sont la plupart des problèmes de corruption de mémoire.

par exemple:

char a[8];
memset(&a[0], 0, 16);

: /*use array a doing some thing */

il est très possible d'être normal en mode debug quand on exécute le code.

mais en sortie, ce serait / pourrait être crash.

pour moi, fouiller là où la mémoire est hors de limite est trop pénible.

utilisez certains outils comme Détecteur de fuite visuel (windows) ou valgrind (linux) sont des choix PLUS JUDICIEUX.

1
répondu Gaiger Chen 2015-03-28 20:15:28

une excellente façon de déboguer une erreur comme celle-ci est d'activer les optimisations pour votre construction de débogage.

1
répondu Mgill404 2017-02-06 19:07:33

j'ai vu beaucoup de bonnes réponses. Cependant, il n'en est aucun qui m'ont aidé. Dans mon cas, il y avait un usage erroné du SSE instructions avec le non aligné mémoire . Jetez un coup d'oeil à votre bibliothèque de mathématiques (si vous en utilisez une), et essayez de désactiver le support SIMD, recompiler et reproduire le crash.

exemple:

"151910920 Un projet" comprend mathfu , et utilise les classes avec le vecteur STL: std::vecteur< mathfu:: vec2 > . Une telle utilisation causera probablement un crash lors de la construction de l'article mathfu::vec2 puisque L'allocateur par défaut STL ne garantit pas l'alignement requis de 16 octets. Dans ce cas pour prouver l'idée, on peut définir #define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1 avant chaque inclure du mathfu , recompiler dans la configuration de libération et vérifier à nouveau.

le Debug et RelWithDebInfo les configurations ont bien fonctionné pour mon projet, mais pas pour celui Release . La raison de ce comportement est probablement due au fait que le débogueur traite les requêtes d'allocation/deallocation et fait une certaine comptabilité de mémoire pour vérifier et vérifier les accès à la mémoire.

j'ai vécu la situation dans les environnements Visual Studio 2015 et 2017.

1
répondu Vlad Serhiienko 2018-05-01 15:15:12

quelque chose de semblable m'est arrivé une fois avec GCC. Il s'est avéré que c'était une optimisation trop agressive qui a été activée seulement lors de la création de la version finale et non pendant le processus de développement.

Eh bien, pour dire la vérité, c'était ma faute, pas celle de gcc, car je n'avais pas remarqué que mon code reposait sur le fait que cette optimisation particulière n'aurait pas été faite.

il m'a fallu beaucoup de temps pour le tracer et je ne suis venu à elle parce que je demandé sur un forum de discussion et quelqu'un m'a fait réfléchir à ce sujet. Alors, permettez-moi de retourner la faveur, juste au cas où cela vous arrive aussi.

0
répondu Remo.D 2008-10-09 07:26:32

j'ai trouvé cet cet article utile pour votre scénario. ISTR les options du compilateur étaient un peu dépassées. Regardez autour de vos options de projet Visual Studio pour voir comment générer des fichiers pdb pour votre compilation de version, etc.

0
répondu fizzer 2008-10-09 07:34:21

il est suspect que cela se passe en dehors du Débogueur et non à l'intérieur; exécuter dans le débogueur ne change normalement pas le comportement de l'application. Je vérifierais les différences d'environnement entre la console et L'IDE. Aussi, évidemment, compilez la version sans optimisations et avec des informations de débogage, et voyez si cela affecte le comportement. Enfin, consultez les outils de débogage post-mortem que d'autres personnes ont suggérés ici, habituellement vous pouvez obtenir quelques indices de leur part.

0
répondu Nick 2008-10-09 07:46:18

déboguer les versions peut être pénible à cause des optimisations qui modifient l'ordre dans lequel les lignes de votre code semblent être exécutées. Ça peut vraiment être déroutant!

une technique pour au moins réduire le problème est D'utiliser MessageBox () pour afficher des déclarations rapides indiquant quelle partie du programme votre code a obtenu ("démarrage Foo ()", " démarrage Foo2 ()"); commencer à les mettre au sommet des fonctions dans la zone de votre code que vous soupçonnez (qu'étiez-vous en train de faire au moment où il s'est écrasé?). Lorsque vous pouvez dire quelle fonction, changez les boîtes de message en blocs de code ou même en lignes individuelles au sein de cette fonction jusqu'à ce que vous rétréciez à quelques lignes. Ensuite, vous pouvez commencer à imprimer la valeur des variables pour voir dans quel état elles sont au point de s'écraser.

0
répondu 2008-10-09 08:24:28

Essayez d'utiliser _CrtCheckMemory() pour voir quel est l'état de la mémoire allouée . Si tout va bien, _CrtCheckMemory retourne vrai , sinon faux .

0
répondu Vhaerun 2008-10-09 10:14:35

vous pouvez lancer votre logiciel avec des options globales activées (regardez dans Outils de débogage pour Windows). Il sera très souvent aider à clouer le problème.

0
répondu Marcin Gil 2008-10-09 11:48:15

permet à votre programme de générer un mini dump lorsque l'exception se produit, puis de l'ouvrir dans un débogueur (par exemple, dans WinDbg). Les principales fonctions à examiner: MiniDumpWriteDump, SetUnhandledExceptionFilter

0
répondu mikhailitsky 2008-12-10 14:33:22

voici un cas que j'avais que quelqu'un pourrait trouver instructif. Il ne s'est écrasé que dans la version de Qt Creator - pas dans debug. J'ai été en utilisant .fichiers ini (comme je préfère les applications qui peuvent être copiées sur d'autres disques, par rapport à ceux qui perdent leurs paramètres si le Registre est corrompu). Cela s'applique à toutes les applications qui stockent leurs paramètres dans les applications' arborescence de répertoire. Si les compilations debug et release sont sous des répertoires différents, vous pouvez aussi avoir un paramètre différent entre eux. J'ai eu préférence vérifiée dans l'un qui n'a pas été vérifiée dans l'autre. Il s'est avéré être la source de mon accident. Bonne chose, je l'ai trouvé.

je déteste le dire, mais je n'ai diagnostiqué le crash que dans MS Visual Studio Community Edition; après avoir installé VS, avoir laissé mon application crash dans Qt Creator, et avoir choisi de l'ouvrir dans le débogueur Visual Studio . Alors que mon application Qt n'avait pas d'information sur les symboles, il s'avère que les bibliothèques Qt en avaient. Il m'a conduit à la délinquance car je pouvais voir quelle méthode était appelée. (Pourtant, je pense que Qt est un cadre LGPL pratique, puissant et multiplateformes.)

0
répondu CodeLurker 2018-10-04 23:47:20

j'ai eu cette erreur et vs s'est écrasé même en essayant de !nettoyer! mon projet. Donc j'ai supprimé les fichiers obj manuellement à partir du répertoire Release, et après ça il s'est bien construit.

-3
répondu Chris89 2014-10-09 11:12:43

Je suis D'accord avec Rolf. Parce que la reproductibilité est si importante, vous ne devriez pas avoir un mode de non-débogage. Toutes vos constructions devraient être déboguables. Avoir deux cibles pour déboguer plus que doubler votre charge de débogage. Il suffit d'envoyer la version "debug mode", à moins qu'elle ne soit inutilisable. Dans ce cas, le rendre utilisable.

-6
répondu wnoise 2008-10-09 07:52:03