J'ai un programme qui lance une exception non interceptée quelque part. Tout ce que j'obtiens, c'est un rapport sur une exception lancée, et aucune information sur l'endroit où elle a été lancée. Il semble illogique pour un programme compilé de contenir des symboles de débogage de ne pas me notifier où dans mon code une exception a été générée.
Existe-t-il un moyen de savoir d'où viennent mes exceptions sans définir 'catch throw' dans gdb et appeler une trace pour chaque exception levée?
Réponses:
Voici quelques informations qui peuvent être utiles pour déboguer votre problème
Si une exception n'est pas interceptée, la fonction de bibliothèque spéciale
std::terminate()
est automatiquement appelée. Terminate est en fait un pointeur vers une fonction et la valeur par défaut est la fonction de bibliothèque C standardstd::abort()
. Si aucun nettoyage n'a lieu pour une exception non interceptée † , cela peut en fait être utile pour déboguer ce problème car aucun destructeur n'est appelé.† Il est défini par l'implémentation, que la pile soit déroulée ou non avant d'
std::terminate()
être appelée.Un appel à
abort()
est souvent utile pour générer un vidage de mémoire qui peut être analysé pour déterminer la cause de l'exception. Assurez-vous d'activer les vidages de mémoire viaulimit -c unlimited
(Linux).Vous pouvez installer votre propre
terminate()
fonction en utilisantstd::set_terminate()
. Vous devriez pouvoir définir un point d'arrêt sur votre fonction de terminaison dans gdb. Vous pourrez peut- être générer une trace arrière de pile à partir de votreterminate()
fonction et cette trace arrière peut aider à identifier l'emplacement de l'exception.Il y a une brève discussion sur les exceptions non détectées dans la pensée de Bruce Eckel en C ++, 2e édition qui peut également être utile.
Depuis les
terminate()
appelsabort()
par défaut (ce qui provoquera unSIGABRT
signal par défaut), vous pourrez peut- être définir unSIGABRT
gestionnaire, puis imprimer une trace de pile à partir du gestionnaire de signaux . Cette trace arrière peut aider à identifier l'emplacement de l'exception.Remarque: je dis peut parce que C ++ prend en charge la gestion des erreurs non locales via l'utilisation de constructions de langage pour séparer la gestion des erreurs et le code de rapport du code ordinaire. Le bloc catch peut être, et est souvent, situé dans une fonction / méthode différente de celle du point de lancement. On m'a également fait remarquer dans les commentaires (merci Dan ) qu'il est défini par l'implémentation que la pile soit déroulée ou non avant d'
terminate()
être appelée.Mise à jour: J'ai lancé un programme de test Linux appelé qui génère une trace dans une
terminate()
fonction définie viaset_terminate()
et une autre dans un gestionnaire de signaux pourSIGABRT
. Les deux backtraces affichent correctement l'emplacement de l'exception non gérée.Mise à jour 2: Grâce à un article de blog sur la capture d'exceptions non interceptées dans terminate , j'ai appris quelques nouvelles astuces; y compris la relance de l'exception non interceptée dans le gestionnaire de terminaison. Il est important de noter que l'
throw
instruction vide dans le gestionnaire de terminaison personnalisé fonctionne avec GCC et n'est pas une solution portable.Code:
Production:
la source
main
), puis elle appelleraitterminate()
. Mais votre exemple montre qu'aucun déroulement n'est fait du tout, ce qui est très cool.throw(int)
spécification est inutile. 2) Leuc->uc_mcontext.eip
est probablement très dépendant de la plate-forme (par exemple, utilisation...rip
sur une plate-forme 64 bits). 3) Compilez avec-rdynamic
pour obtenir des symboles de suivi. 4) Courez./a.out 2>&1 | c++filt
pour obtenir de jolis symboles de traces.((sig_ucontext_t *)userContext)->uc_mcontext.fault_address;
travaillé pour ma cible ARMComme vous le dites, nous pouvons utiliser 'catch throw' dans gdb et appeler 'backtrace' pour chaque exception levée. Bien que cela soit généralement trop fastidieux à faire manuellement, gdb permet l'automatisation du processus. Cela permet de voir la trace de toutes les exceptions levées, y compris la dernière non interceptée:
gdb>
Sans autre intervention manuelle, cela génère de nombreuses backtraces, dont une pour la dernière exception non interceptée:
Voici un excellent article de blog pour conclure ceci: http://741mhz.com/throw-stacktrace [sur archive.org]
la source
Vous pouvez créer une macro comme:
... et il vous donnera l'emplacement où l'exception est lancée (certes pas la trace de pile). Il est nécessaire que vous dériviez vos exceptions à partir d'une classe de base qui prend le constructeur ci-dessus.
la source
throw new excation(...)
maisthrow exception(...)
C ++ n'est pas Java,Vous n'avez pas transmis d'informations sur le système d'exploitation / compilateur que vous utilisez.
Dans Visual Studio C ++, les exceptions peuvent être instrumentées.
Voir «Instrumentation de gestion des exceptions Visual C ++» sur ddj.com
Mon article "Postmortem Debugging" , également sur ddj.com, inclut du code pour utiliser la gestion des exceptions structurée Win32 (utilisée par l'instrumentation) pour la journalisation, etc.
la source
Vous pouvez marquer les principaux endroits serrés dans votre code
noexcept
pour localiser une exception, puis utiliser libunwind (ajouter simplement-lunwind
aux paramètres de l'éditeur de liens) (testé avecclang++ 3.6
):demagle.hpp:
demangle.cpp:
backtrace.hpp:
backtrace.cpp:
backtrace_on_terminate.hpp:
Il y a un bon article sur la question.
la source
J'ai du code pour le faire dans Windows / Visual Studio, faites-moi savoir si vous voulez un aperçu. Je ne sais pas comment le faire pour le code dwarf2 cependant, un rapide google suggère qu'il existe une fonction _Unwind_Backtrace dans libgcc qui fait probablement partie de ce dont vous avez besoin.
la source
Vérifiez ce fil, cela aide peut-être:
Attraper toutes les exceptions C ++ non gérées?
J'ai fait de bonnes expériences avec ce logiciel:
http://www.codeproject.com/KB/applications/blackbox.aspx
Il peut imprimer une trace de pile dans un fichier pour toute exception non gérée.
la source
exception thrown foo.c@54, ..., re-thrown bar.c@54, ....
sans avoir à le faire manuellement.