Segfault

Résolu
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 - 14 oct. 2009 à 23:12
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 - 17 oct. 2009 à 10:17
Bonjour,

J'essaye d'éliminer un maximum toutes les erreurs de segfault pouvant intervenir dans mes classes et je butte sur un point.

Pour comprendre j'ai fait un code de démonstration :
#include <cstdlib>
#include 

using namespace std;

class A
{
    public:
        virtual void methode1() = 0;
};

class B: public A
{
    public:
        void methode1()
        {
            if (this == NULL)
            {
                cout << "INSTANCE INVALIDE" << endl;
            }
            else
            {
                cout << "INSTANCE VALIDE" << endl;
            }
        }
        
        void methode2()
        {
            if (this == NULL)
            {
                cout << "INSTANCE INVALIDE" << endl;
            }
            else
            {
                cout << "INSTANCE VALIDE" << endl;
            }
        }
};

inline B& invalide()
{
    return ( *( (B*)NULL ) );
}

int main(int argc, char *argv[])
{
    B b;
    
    cout << "\n-- INSTANCE VALIDE --" << endl;
    b.methode2();
    b.methode1();
    
    cout << "\n-- INSTANCE INVALIDE --" << endl;
    invalide().methode2();
    invalide().methode1(); // Plantage ici
    
    system("PAUSE");
    return EXIT_SUCCESS;
}


Si vous avez des idées ou mieux la solution, je prends.

Merci d'avance et bonne prog,
@++

Victor
A voir également:

7 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
15 oct. 2009 à 22:24
Ce n'est pas vraiment possible. Si le programme plante, il plante !
Tu ne peux pas vraiment gérer ça. En effet, l'utilisateur qu'il voit: "segfault" ou "Un problème technique est survenue, merci de contacter etc...", il ne pourra pas faire grand chose.

Lorsque ce type d'erreur survient, on demande généralement au client de:
- Décrire ce qu'ils ont fait, pour reproduire le problème.
- Récupérer le core dump, qui contient la stack trace des derniers événement avant erreur.

Je comprends ton besoin, mais avec ta technique, tu vas inutilement complexifier le code. C'est beaucoup trop intrusif. Si c'est vraiment ce que tu veux, dans ce cas, fait toi une classe "SandBox" qui entoure chacun des classes, et en cas d'erreur affiche une erreur contenant le nom de la classe en cause (pas top, et encore trop intrusif à mon goût).

Une deuxième technique, utilisé notamment en java, est de créer un logger. Tu logges tout ce que tu peux, et en cas d'erreur, tu met simplement un "try{}catch(...){}" dans ton "main()", et tu propose à l'utilisateur d'envoyer le dit rapport.

PS:
Un autre moyen d'attraper un "segfault", est de se lier a ce signal:

#include 
#include <csignal>
#include <cstdlib>

void onError(int)
{
  // Prevent infinite recursion if onError() causes another segfault
  std::signal(SIGSEGV, SIG_DFL);

  std::cout << "Segfault spotted !" << std::endl;
  std::abort();
}

int main ()
{
  std::signal(SIGSEGV, onError);
  int *p = 0;
  *p = 0; // Segfault

  return 0;
}


Il n'y a de toute façon pas de solution miracle :)
3
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 7
17 oct. 2009 à 10:17
Bonjour,

Ce code m'a l'air intéressant pour ce que je veux.

Sinon j'ai lu que les fonctions virtuelles sont liés (grâce à une VTABLE) à l'exécution et non à la compilation. Ce qui fait que le corps de la méthode n'est pas appelée avant que le programme plante.

Donc à part catcher un segfault, on ne peux pas faire grand chose.

Merci pour ton aide.

Bonne prog,
@++

Victor
3
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 7
14 oct. 2009 à 23:20
Bonjour,

On peut maintenant y ajouter des exceptions :
#include <cstdlib>
#include 

using namespace std;

class A
{
    public:
        virtual void methode1() = 0;
};

class B: public A
{
    public:
        void methode1()
        {
            if (this == NULL)
            {
                cout << "INSTANCE INVALIDE" << endl;
                throw 0;
            }
            else
            {
                cout << "INSTANCE VALIDE" << endl;
            }
            cout << "METHODE 1" << endl;
        }
        
        void methode2()
        {
            if (this == NULL)
            {
                cout << "INSTANCE INVALIDE" << endl;
                throw 0;
            }
            else
            {
                cout << "INSTANCE VALIDE" << endl;
            }
            cout << "METHODE 2" << endl;
        }
};

inline B& invalide()
{
    return ( *( (B*)NULL ) );
}

int main(int argc, char *argv[])
{
    B b;
    
    cout << "\n-- INSTANCE VALIDE --" << endl;
    b.methode2();
    b.methode1();
    
    cout << "\n-- INSTANCE INVALIDE --" << endl;
    try
    {
        invalide().methode2();
    }
    catch(...)
    {
        cout << "EXCEPTION METHODE 2" << endl;
    }
    try
    {
        invalide().methode1(); // Plantage ici
    }
    catch(...)
    {
        cout << "EXCEPTION METHODE 1" << endl;
    }
    
    system("PAUSE");
    return EXIT_SUCCESS;
}


Voici la sortie avant le plantage du programme :
-- INSTANCE VALIDE --
INSTANCE VALIDE
METHODE 2
INSTANCE VALIDE
METHODE 1

-- INSTANCE INVALIDE --
INSTANCE INVALIDE
EXCEPTION METHODE 2


Merci et bonne prog,
@++

Victor
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
15 oct. 2009 à 00:34
Ce genre d'erreur fait partit de celle qui ne devrait pas arriver. Personnellement, j'utilise des assert.


#include <cassert>

assert(this);
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 7
15 oct. 2009 à 18:21
Bonjour,

> Ce genre d'erreur fait partit de celle qui ne devrait pas arriver.
C'est pour ça que je veux générer une erreur sans faire planter le programme si jamais ça arrive.

assert n'est qu'une macro qui affiche un message d'erreur insuffisant au niveau compréhension pour un utilisateur lambda.

Si tu as d'autres idées, fais moi signe.

Merci de ton aide.

Bbonne prog,
@++

Victor
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
15 oct. 2009 à 18:38
assert n'est qu'une macro qui affiche un message d'erreur insuffisant au niveau compréhension pour un utilisateur lambda.

Tu n'as donc pas compris assert.

Je vais m'expliquer. Il y a deux types d'erreur:
- L'erreur possible. C'est à dire, une erreur qui est "normale". Exemple classique: impossibilité d'ouvrir un fichier.
On utilise pour cela une gestion d'erreur. (code de retour, exceptions, ...).
- L'erreur qui ne doit pas arriver. Généralement, c'est un bug de l'application. Exemple typique: oublie d'allouer une classe.
Ce type d'erreur ne doit pas faire partie de l'application, et en ce sens être corrigée. C'est en ça qu'"assert" est utile. Ca te permet en mode debug, de t'assurer de la robustesse de ton code. Si un assert est déclenché, tu as immédiatemment la ligne et le fichier ou s'est produit le problème. Avoir un code bourré d'assert est gage de qualité, et de robustesse.
Ce n'est pas absolument pas destiné à un utilisateur. D'ailleurs, en mode release, les assert sont automatiqument effacés !

Il faut bien différencier ces deux cas, et le code d'exemple que tu as écrit, est clairement dans le second cas.
0
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 7
15 oct. 2009 à 19:33
Bonjour,

Je suis d'accord avec toi mais imaginons que tu fasse une classe qui risque d'être maltraitée par d'autres développeur.

Si tu place des assert et que le développeur n'a jamais eu le cas d'un segfault (parce qu'il n'a pas prévu tous les cas), c'est l'utilisateur en release qui va voir son programme planter et le développeur ne sait pas quoi faire.
Si le développeur lui affiche une erreur dîte technique (dû à une mauvaise programmation qui s'oppose à applicative où l'utilisateur est en cause) l'utilisateur peut continuer à utiliser l'application ou pas mais le développeur saura qu'est-ce qui ne va pas et où.

Merci et bonne prog,
@++

Victor
0
Rejoignez-nous