web-dev-qa-db-fra.com

Résoudre des accidents aléatoires

Je reçois des accidents aléatoires sur mon application C++, il ne peut pas se bloquer pendant un mois, puis collaborer 10 fois dans une heure, et parfois, il peut parfois s'écraser lors de son lancement, tandis que cela peut parfois se bloquer après plusieurs heures d'ouverture (ou pas tous).

J'utilise GCC sur GNU/Linux et MinGW sous Windows, je ne peux donc pas utiliser Visual Studio JIT de débogage ...

Je ne sais pas sur la façon de procéder, à la recherche au hasard sur le code ne travaillerait, le code est énorme (et une bonne partie était pas mon travail, aussi il a une bonne quantité de choses existant à ce sujet), et je ne pas non plus avoir un indice sur la façon de reproduire l'accident.

EDIT: Beaucoup de gens ont mentionné que ... comment je fais une volets de base, miniDump ou quel que soit? C'est la première fois que j'ai besoin de débogage postmortem.

EDIT2: En fait, DrMingw capturé une pile d'appel, pas d'info mémoire ... Malheureusement, la pile d'appels ne me pas aidé beaucoup, car à la fin soudainement aller dans une bibliothèque (ou quelque chose) que je n'ai pas les informations de débogage , ce qui ne en quelques chiffres hexadécimaux ... Alors je encore besoin d'un peu décent décharge qui donnent plus d'informations (en particulier sur ce qui était dans la mémoire ... plus précisément, ce qui était dans l'endroit qui a donné l'erreur " violation d'accès ")

De plus, mon application utilise Lua et Luabind, peut-être que l'erreur est dû à un script .Lua, mais je n'ai aucune idée de la façon de déboguer cela.

35
speeder

Tout d'abord, vous avez de la chance que votre processus s'écroule plusieurs fois dans une courte période. Cela devrait faciliter la poursuite.

Voici comment vous procédez.

  • Obtenir un déchargement
  • Isoler un ensemble de fonctions suspectes potentielles
  • Serrer la vérification de l'état
  • Répéter

Obtenez un dépotoir de crash

Tout d'abord, vous devez vraiment avoir une décharge de crash.

Si vous ne recevez pas de décharges de crash lorsqu'il se bloque, commencez par écrire un test qui produit des décharges de collision fiables.

Re-compiler les symboles binaires avec des symboles de débogage ou vous assurer que vous pouvez analyser le dépotoir de crash avec des symboles de débogage.

Trouvez des fonctions suspectes

Étant donné que vous avez une décharge de crash, regardez-la dans GDB ou votre débogueur préféré et n'oubliez pas de montrer toutes les discussions! Ce n'est peut-être pas le fil que vous voyez dans GDB qui est buggy.

En regardant où GDB dit que votre binaire s'est écrasé, isoler un ensemble de fonctions que vous pensez causer le problème.

En regardant plusieurs crashs et isolant des sections de code qui sont couramment actifs dans tous les accidents sont un économiseur de temps réel.

Serrez la vérification de l'état

Un crash se produit généralement parce qu'un état incompatible. La meilleure façon de procéder est souvent de resserrer les exigences de l'État. Vous faites cela la manière suivante.

Pour chaque fonction, vous pensez peut-être causer le problème, documenter quel état juridique l'entrée ou l'objet doit avoir sur l'entrée de la fonction. (Faites de même pour quel état juridique il doit avoir à la sortie de la fonction, mais ce n'est pas trop important).

Si la fonction contient une boucle, documentez l'état juridique qu'il doit avoir au début de chaque itération de la boucle.

Ajouter des affirmations pour toutes ces expressions d'état juridique.

répéter

Puis répétez le processus. Si cela se bloque toujours en dehors de vos affirmations, resserrez davantage les affirmations. À un moment donné, le processus s'effondrera sur une affirmation et non à cause d'un accident aléatoire. À ce stade, vous pouvez vous concentrer sur la tentative de déterminer ce que votre programme a effectué votre programme d'un État juridique à l'entrée de la fonction, à un état illégal au point où l'affirmation s'est produite.

Si vous associez les affirmations avec la journalisation de Verbose, il devrait être plus facile de suivre ce que fait le programme.

15
user239558

Si tout le reste échoue (en particulier si la performance sous le débogueur est inacceptable), une exploitation forestière étendue. Démarrer avec les points d'entrée - est l'application transactionnelle? Connectez-vous chaque transaction au fur et à mesure de son entrée. Connectez-vous tous les appels de constructeur pour vos objets clés. Étant donné que le crash est tellement intermittent, des appels de journaux à toutes les fonctions qui pourraient ne pas être appelées tous les jours.

Vous commencerez au moins se rétrécir là où le crash pourrait être.

14
Nicholas Knight

Lorsque je travaille, les programmes de collision génèrent généralement un fichier de butée de base qui peut être chargé dans Windbg.

Nous avons ensuite une image de la mémoire au moment où le programme s'est écrasé. Il n'y a rien grand chose que vous pouvez faire avec cela, mais cela vous donne la dernière pile d'appel. Une fois que vous connaissez la fonction qui s'est écrasée, vous pourriez alors être capable de suivre le problème, vous pouvez au moins réduire le problème à un essai plus reproductible.

8
ereOn

Démarrer le programme sous le débogueur (je suis sûr qu'il y a un débogueur avec GCC et Mingw) et attendre que cela se bloque sous le débogueur. Au point de crash, vous pourrez voir quelle action spécifique échoue, examinez le code de montage, les registres, l'état de la mémoire - cela vous aidera souvent à trouver la cause du problème.

8
sharptooth

On dirait que votre programme souffre de la corruption de la mémoire. Comme indiqué déjà que votre meilleure option sur Linux est probablement Valgrind. Mais voici deux autres options:

  • Tout d'abord, utilisez A Débug MALLOC . Presque toutes les bibliothèques C offrent une implémentation de débogage MALLOC qui initialise la mémoire (normal MALLOC conserve "OLD" Contenu en mémoire), vérifiez les limites d'un bloc attribué pour la corruption et ainsi de suite. Et si cela ne suffit pas, il existe un large choix d'implémentations tierces.

  • Vous voudrez peut-être consulter VMware Workstation. Je ne l'ai pas configuré de cette façon, mais de leurs supports marketing, ils soutiennent une manière assez intéressante de débogage: exécutez le débuge dans une machine virtuelle "enregistrement". Lorsque la corruption de la mémoire se produit, définissez un point d'arrêt de mémoire à l'adresse corrompue d'une adresse corrompue, alors Témurez le temps de retour dans le VM à exactement que moment où ce morceau de mémoire était écrasé. Voir - ce pdf sur la manière de configurer la relecture du débogage avec Linux/GDB. Je pense qu'il y a une démonstration de 15 ou 30 jours pour le poste de travail 7, qui pourrait suffire à secouer ces bugs de votre code.

6
froh42

Ces sortes de bugs sont toujours difficiles - à moins que vous ne puissiez reproduire l'erreur, votre seule option consiste à apporter des modifications à votre application afin que des informations supplémentaires soient enregistrées, puis attendez que l'erreur arrive à nouveau dans la nature.

Il y a un excellent outil appelé Process Dumper que vous pouvez utiliser pour obtenir un déchargement de crash d'un processus qui confère une exception ou des sorties de manière inattendue - vous pouvez demander aux utilisateurs d'installer et de configurer des règles pour votre application.

Sinon, si vous ne voulez pas demander aux utilisateurs d'installer d'autres applications, vous pouvez utiliser votre moniteur d'applications pour des exceptions et créer une décharge elle-même en appelant MiniCumpwriDeDmp .

L'autre option consiste à améliorer la journalisation, mais de déterminer quelles informations à enregistrer (sans simplement tout enregistrer) peuvent être délicates, et il peut donc prendre plusieurs itérations de Crash - Changer Loging pour chasser le problème.

Comme je l'ai dit, ces types de bugs sont Toujours difficiles à diagnostiquer - dans mon expérience, il s'agit généralement d'heures et d'heures de peering à travers des grumes et des décharges de collision jusqu'à ce que soudainement Vous obtenez ce moment EUREKA où tout a du sens - la clé collecte la bonne information.

6
Justin

Exécutez l'application sur Linux sous valgrind pour rechercher des erreurs de mémoire. Des accidents aléatoires sont généralement inférieurs à la mémoire de corruption.

Fixez chaque erreur que vous trouvez avec l'outil Memcheck de Valgrind, puis, espérons-le, l'accident disparaîtra.

Si l'ensemble du programme prend trop de temps pour fonctionner sous Valgrind, puis diviser la fonctionnalité en tests d'unité et exécutés celles-ci sous Valgrind, vous espérez-vous trouver les erreurs de mémoire qui causent les problèmes.

Si cela ne vous assurez pas que les camedumps sont activés (ulimit -a) Et puis quand il se bloque, vous pourrez savoir où gdb.

4
Douglas Leeder

Vous avez déjà entendu comment gérer cela sous Linux: inspecter les décharges de noyau et exécuter votre code sous Valgrind. Donc, votre première étape pourrait être de trouver les erreurs sous Linux, puis de vérifier si elles disparaissent sous Mingw. Puisque personne n'a mentionné Mudflap Ici, je le ferai: Utilisez de la boue de boue si votre distribution Linux le fournit. Mudflap vous aide à attraper une mauvaise utilisation du pointeur et des débordements de tampon en suivant les informations où un pointeur est réellement autorisé à indiquer:

Et pour Windows: Il y a un débogueur JIT pour Mingw, appelé DRMMERWW:

4
Nordic Mainframe

Cela ressemble à quelque chose de délicat comme une condition de course.

Je vous suggère de créer une construction de débogage et de l'utiliser. Vous devez également vous assurer qu'un vidage de base est créé lorsque le programme se bloque.

La prochaine fois que le programme se bloque, vous pouvez lancer GDB sur le CoreDump et voir où le problème réside. Ce sera probablement une faute consécutive, mais cela devrait vous aider à démarrer.

3
fhd

La première chose que je ferais est de déboguer le dépotoir de base avec GDB (Windows et Linux). La seconde fonctionnerait un programme tel que Lint, Prefast (Windows), Analyser Clang ou un autre programme d'analyse statique (préparez-vous à beaucoup de faux positifs). Troisième chose serait une sorte de vérification d'exécution, comme Valgrind (ou ses variantes fermées), vérificateur d'application Microsoft , ou Google PerfTools .

Et journalisation. Qui n'a pas besoin d'aller sur le disque. Vous pouvez, par exemple, connectez-vous à un global std::list<std::string> qui serait éliminé aux 100 dernières entrées. Lorsqu'une exception est capturée, affichez le contenu de cette liste.

3
Max Lybbert
  1. Commencer à connecter. Mettez des relevés de journalisation dans des endroits où vous pensez que le code flaky. Concentrez-vous sur le test du code et répétez jusqu'à ce que vous affiez le problème sur un module ou une fonction.

  2. Mettre des affirmations partout!

  3. Pendant que vous y êtes, mettez seulement une expression dans une affirmation.

  4. Écrivez un test de l'unité pour le code que vous pensez échouer. De cette façon, vous pouvez exercer le code de manière isolée du reste de votre environnement d'exécution.

  5. Écrivez plus de tests automatisés qui exercent le code problématique.

  6. N'ajoutez pas plus de code au-dessus du mauvais code qui échoue. C'est juste une idée stupide.

  7. Apprenez à rédiger des mini-décharges et faire du débogage post-mortem. On dirait que les autres ici ont expliqué que très bien.

  8. Faites de l'exercice du mauvais code à partir de différentes manières possibles que vous pouvez vous permettre d'isoler le bogue.

  9. Utilisez une construction de débogage. Exécutez la construction de débogage sous le débogueur si possible.

  10. Coupez votre application en supprimant des fichiers binaires, des modules, etc. Si possible, de sorte que vous puissiez essayer de tenter de reproduire le bogue.

3
C Johnson

Il y a beaucoup de bonnes réponses ici, mais personne n'a encore touché l'angle de Lua.

Lua est généralement assez bien comporté, mais il est toujours possible de causer une corruption de mémoire ou un crash si par exemple. La pile Lua débordent ou des métiers, ou un mauvais bytecode est exécuté.

Une chose facile que vous puissiez faire qui détectera beaucoup de telles erreurs est de définir la macro Lua_Assert à Luaconf.h. Définir cela (à E.g. Standard C Assert) permettra à une variété de contrôles de santé mentale à l'intérieur du noyau LUA.

2
tehtmi

Un autre chèque de base: assurez-vous que vous faire une reconstruction complète de votre projet. Si vous avez modifié divers fichiers (surtout des fichiers d'en-tête) et que vous procédez à des constructions partielles, les choses peuvent vous désordonner si vos dépendances de construction ne sont pas parfaites. Une reconstruction complète supprime simplement cette possibilité.

De plus, pour Windows, consultez Microsoft outils de débogage pour Windows , et en particulier à l'outil gflags .

1
Pierz

Vous avez probablement effectué une erreur de mémoire dans laquelle vous mettez des valeurs à ne pas attribuer d'espace alloué en quelque sorte, c'est une bonne raison pour les accidents aléatoires, pendant un long temps, personne ne tente d'utiliser cette mémoire afin qu'il n'y aura pas d'erreurs, vous pouvez jeter un coup d'œil au endroits où vous allouez de la mémoire et vérifiez où vous utilisez de manière approfondie des pointeurs. Autre que cela, comme d'autres ont souligné que vous devez utiliser une forte journalisation étendue, dans l'écran et les fichiers.

1
LostMohican

Si votre application n'est pas spécifique à Windows, vous pouvez essayer de compiler et d'exécuter votre programme sur d'autres plates-formes telles que Linux (Différentes distributions, 32/64 bits, ... Si vous avez le luxe). Cela peut aider à déclencher les bugs de votre programme. Bien sûr, vous devez utiliser les outils mentionnés dans d'autres messages tels que GDB, Valgrind, etc.

0
tofu

Deux autres pointeurs/idées (en plus de la vidage centrale et de Valgrind sur Linux):

1) Essayez "QT Creator" de Nokia. Il soutient MINGW et peut agir en tant que débogueur post-mortem.

2) Si c'est réalisable, il suffit peut-être d'exécuter constamment l'application dans GDB?

0
Frank Osterfeld