8
votes

Obtenir des informations sur l'endroit où les exceptions C ++ sont lancées à l'intérieur du bloc de capture?

J'ai une application C ++ qui enveloppe de grandes parties du code dans les blocs. Lorsque je saisie des exceptions, je peux retourner l'utilisateur à un état stable, ce qui est agréable. Mais je ne reçois plus de décharges. J'aimerais vraiment comprendre où dans le code l'exception a lieu, je peux donc la connecter et le réparer.

Être capable d'obtenir une décharge sans arrêter l'application serait idéale, mais je ne suis pas sûr que ce soit possible.

Y a-t-il une manière que je puisse comprendre où l'exception a été lancée à l'intérieur du bloc de capture? Si c'est utile, j'utilise MSVC ++ natif sur Windows XP et plus élevé. Mon plan consiste simplement à enregistrer les accidents dans un fichier sur les machines des différents utilisateurs, puis téléchargez les crashlogs une fois qu'ils arrivent à une certaine taille.


1 commentaires

5 Réponses :



2
votes

Vous pouvez écrire des vidages à l'aide de MiniDumpwirshump fonction.

Si vous utilisez des exceptions C ++, vous pouvez simplement inclure les informations de fichier / ligne / fonction (vous le verrez donc comme texte si vous appelez std :: Exception.Que ()) Dans n'importe quel endroit où vous lancez exception (en utilisant ____Fonction____, ____File____ et ____line____ macros).

Si vous essayez d'attraper des exceptions du système d'exploitation, alors écrasez l'application sera probablement un meilleur choix.


0 commentaires

6
votes

Ceci est possible avec l'utilisation de SEH (manipulation de l'exception structurée). Le point est que MSVC implémente les exceptions c ++ via SEH. D'autre part, le SEH pur est beaucoup plus puissant et flexible.

C'est ce que vous devriez faire. Au lieu d'utiliser des blocs PURE C ++ ESSAY / CATTENNES comme celui-ci: P>

void DoSomething()
{
    __try {
        DoSomethingInner();
    }
    __except (DumpExc(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) {
        // never get there
    }
}

void DumpEx(EXCEPTION_POINTERS* pExc)
{
    // Call MiniDumpWriteDump to produce the needed dump file
}


10 commentaires

Utiliser SEH directement est OK si vous vous souciez de la portabilité. Les exceptions standard C ++ sont plus portables (puits, à l'exception de plusieurs compilateurs pour systèmes embarqués qui ne prennent pas en charge les exceptions).


C'est un moyen efficace de gérer les exceptions c ++. Si vous souhaitez obtenir des informations utiles sur les exceptions du système d'exploitation, telles que le débordement de la pile ou la violation d'accès, vous devez organiser un MiniDumpwriDeDmp à appeler à partir d'un autre processus.


@George: Il n'y a actuellement aucun moyen portable pour obtenir des traces de pile en C ++. Je semble rappeler que c'est une situation que la nouvelle norme C ++ 0X tente d'améliorer.


Pas nécessairement. Eh bien, si vous parlez de débordement de pile et que vous gérez cette exception avant que la pile ne se déroule - vous devriez appeler «MiniDumpwridressump» d'un autre fil (puisque notre thread n'a presque pas de pile). Mais il n'y a pas besoin de faire des choses d'un autre processus. Sauf si vous envisagez l'exception en tant que bogue, et ne vous appuyez pas sur ce processus


@BEN VOIGT: C'est surtout vrai (il existe des méthodes pour ce faire qui fonctionnent correctement pour Win32 W / Mingw, Cygwin & Linux), mais utiliser SEH garantit le code ne construira pas sur une autre plate-forme, à moins que vous ne décidiez de vous gêner avec le préprocesseur.


@valdo: MiniDumpwriDeDmp doit charger d'autres DLL. Si vous avez rencontré une exception tout en maintenant la serrure du chargeur, vous feriez mieux de l'appeler à partir du processus. De plus, si vous avez une corruption de mémoire (une cause commune de bugs que vous voudriez avoir une décharge), vous devriez à nouveau appeler miniduumpwridamep hors processus.


Si DosomOnner appelle Winapi sendMessage () et c ++ exception est survenu dans son gestionnaire (c'est mon code aussi), benneXc () n'est pas tiré. et le débogueur affiche un avertissement sur une exception non gérée. Pourquoi?


@ 23W: Parlez-vous d'une exception non conventionnelle (qui est un crash plutôt que d'avertissement), ou un message de débogueur d'exception de 1ère chance? Si ce dernier est le cas, alors c'est probablement parce que sendmessage a son propre gestionnaire de Seh, qui gère cette exception.


@Valdo, sur un message de débogueur d'exception de 1ère chance


SEH impose des restrictions sérieuses sur ce que le code à l'intérieur du bloc peut faire. Je n'ai pas utilisé Seh pendant un moment, mais la dernière fois que j'ai essayé, cela ne permettait pas d'obtenir des objets dans le cadre local qui avaient des destructeurs.



1
votes

Un astuce qui est compilateur indépendant consiste à envelopper la déclaration de lancer dans une fonction. La fonction peut effectuer d'autres tâches avant de lancer l'exception, telles que l'enregistrement dans un fichier journal. Cela fait également un endroit pratique pour mettre un point d'arrêt. Si vous créez une macro pour appeler la fonction, vous pouvez incluez automatiquement le fichier __ __ et __ ligne __ où le lancer est survenu.


0 commentaires

4
votes

Il est possible de concevoir vos exceptions pour inclure les noms de fichiers source et les numéros de ligne. Pour ce faire, vous devez créer une classe dérivée de std :: exception code> pour contenir les informations. Dans l'exemple ci-dessous, j'ai une bibliothèque d'exceptions pour mon application, y compris my_exception code>. J'ai aussi un traced_error code> une classe d'exception de modèle dérivée de mes exceptions de niveau d'application. L'exception traced_error code> contient des informations sur le nom de fichier et le numéro de fichier, puis appelle la classe d'exception de niveau d'application ' what () code> méthode pour obtenir des informations d'erreur détaillées.

#include <cstdlib>
#include <string>
#include <stdexcept>
#include <iostream>
using namespace std;


template<class EX>
class traced_error : virtual public std::exception, virtual public EX
{
public:
    traced_error(const std::string& file, int line, const EX& ex)
    :   EX(ex),
        line_(line),
        file_(file)
    {       
    }

    const char* what() const
    {
        std::stringstream ss;
        static std::string msg;
        ss << "File: " << file_ << " Line: " << line_ << " Error: " << EX::what();
        msg = ss.str().c_str();
        return msg.c_str();
    }

    int line_;
    std::string file_;
};

template<class EX> traced_error<EX> make_traced_error(const std::string& file, int line, const EX& ex)
{
    return traced_error<EX>(file, line, ex);
}


class my_exception : virtual public std::exception
{
public:
    my_exception() {};

    const char* what() const
    {
        return "my_exception's what";
    }
};

#define throwx(EX) (throw make_traced_error(__FILE__,__LINE__,EX))


int main()
{
    try
    {
        throwx(my_exception());
    }
    catch( const std::exception& ex )
    {
        cout << ex.what();
    }
    return 0;
}


0 commentaires