Question

J'ai un programme qui sépare parfois l'arithmétique du pointeur.Je sais que cela se produit, mais je ne peux pas facilement vérifier à l'avance s'il s'agit d'une erreur de segmentation ou non - soit je peux "pré-analyser" les données d'entrée pour voir si cela provoquera une erreur de segmentation (ce qui peut être impossible à déterminer), ou je peux le réadapter pour ne pas utiliser l'arithmétique du pointeur, ce qui nécessiterait une quantité de travail beaucoup plus importante, ou je peux essayer de détecter une erreur de segmentation.Alors ma question :

1) Comment, en C, puis-je détecter une erreur de segmentation ?Je sais quelque chose dans le système d'exploitation provoque une erreur de segmentation, mais que peut faire un programme C dans le cas où il échoue pour mourir un peu plus gracieusement que simplement Segmentation fault?

2) Dans quelle mesure est-ce portable ?

J'imagine que c'est un comportement hautement non portable, donc si vous publiez du code pour détecter une erreur de segmentation, dites-moi sur quoi cela fonctionne.Je suis sous Mac OS X mais j'aimerais que mon programme fonctionne sur autant de plates-formes que possible et je veux voir quelles sont mes options.

Et ne vous inquiétez pas, tout ce que je veux faire, c'est imprimer un message d'erreur plus convivial et en libérer quelques-uns. malloc()ed mémoire, puis mourir.Je n'ai pas l'intention d'ignorer toutes les erreurs de segmentation que je reçois et d'aller de l'avant.

Était-ce utile?

La solution

Vous devez définir un gestionnaire de signal.Cela se fait sur les systèmes Unix en utilisant la fonction sigaction.Je l'ai fait avec le même code sur Fedora 64 et 32 ​​bits et sur Sun Solaris.

Autres conseils

Eh bien, SIGSEGV est trappable, ce qui est Posix, il est donc portable en ce sens.

Bu Je crains que vous semblez vouloir gérer la segfault plutôt que de résoudre le problème qui provoque l'erreur de segmentation. Si je devais choisir que ce soit le système d'exploitation en faute, ou mon propre code, je sais que je choisirais. Je vous suggère de traquer ce bug, corriger, puis d'écrire un test pour vous assurer qu'il ne vous mord à nouveau.

Vous pouvez utiliser la fonction signal de pour installer un nouveau gestionnaire de signal pour le signal:

   #include <signal.h>
   void (*signal(int signum, void (*sighandler)(int)))(int);

Quelque chose comme le code suivant:

signal(SIGINT , clean_exit_on_sig);
signal(SIGABRT , clean_exit_on_sig);
signal(SIGILL , clean_exit_on_sig);
signal(SIGFPE , clean_exit_on_sig);
signal(SIGSEGV, clean_exit_on_sig); // <-- this one is for segmentation fault
signal(SIGTERM , clean_exit_on_sig);

void 
clean_exit_on_sig(int sig_num)
{
        printf ("\n Signal %d received",sig_num);
}

Les actions de sécurité dans un gestionnaire de signaux sont très limitée. Il est dangereux d'appeler une fonction de bibliothèque ne sait pas être rentrante, ce qui exclut, par exemple, free() et printf(). La meilleure pratique consiste à définir une variable et retour, mais cela ne vous aide pas beaucoup. Il est également sûr d'utiliser les appels système tels que write().

Notez que dans les deux exemples de backtrace donnés ici, la fonction backtrace_symbols_fd() sera en sécurité, car il utilise directement le fd brut, mais l'appel à fprintf() est incorrect, et doit être remplacée par une utilisation de write().

Je pense que vous essayez de résoudre un problème qui n'existe pas. Au moins vous travaillez sur la mauvaise fin. Vous ne serez pas en mesure de prises une erreur de segmentation, comme cette erreur / exception est levée par le système d'exploitation (il est causé par votre programme, le système d'exploitation que prises il).

Je vous conseille de repenser votre stratégie en ce qui concerne l'entrée: Pourquoi est-il impossible de le désinfecter? Le plus important à faire est de vérifier la taille, pour ce C stdlib a des fonctions appropriées. Alors bien sûr, vous devriez vérifier une entrée valide en ce qui concerne le contenu. Oui, cela se traduira probablement beaucoup de travail, mais il est la seule façon d'écrire un programme solide.

EDIT: Je ne suis pas beaucoup plus d'un expert en C, ne savait pas que même une erreur de segmentation pourrait être gérée par un gestionnaire de signal. Pourtant, je pense que ce n'est pas la bonne façon de faire pour les raisons mentionnées ci-dessus.

Vous devrez fournir un gestionnaire SIGSEGV, celui-ci semble tout à fait décent .

traitement du signal est (relativement) portable entre toutes les machines unix (cela inclut mac et linux). Les grandes différences sont dans les détails d'exception, qui est passé comme argument à la routine de traitement du signal. Sorrty, mais vous aurez probablement besoin d'un tas de #ifdefs pour que, si vous souhaitez imprimer les messages d'erreur plus raisonnables (par exemple lorsque et en raison de laquelle l'adresse de la faute passé) ...

ok, voici un fragment de code pour vous de commencer avec:

#include <signal.h>

/* reached when a segv occurrs */
void
SEGVFunction( SIGARGS )
{
     ...
}

...
main(...) {
    signal(SIGSEGV, SEGVFunction); /* tell the OS, where to go in case... */
    ...
    ... do your work ...
}

Votre tâche consiste à:

  • vérifier ce que SIGARGS est (OS à charge, utilisez donc un ifdef)
  • voir comment extraire adresse de défaut et PC à partir des informations d'exception dans sigArgs
  • imprimer un message raisonnable
  • exit

en théorie, vous pourriez même patcher le PC dans le gestionnaire de signal (à après l'instruction de la formation de failles), et continuez. Cependant, les gestionnaires de signaux typiques soit sortie () ou à un longjmp () retour en lieu sûr dans le principal.

concerne

Il y a un exemple de la façon d'attraper SIGSEGV et imprimer une trace de la pile en utilisant la glibc backtrace () ici:

comment générer un stacktrace quand mon C ++ application plante

Vous pouvez l'utiliser pour attraper votre segfault et nettoyer, mais attention: vous ne devriez pas faire trop de choses dans un gestionnaire de signaux, en particulier des choses qui impliquent de faire des appels comme malloc (). Il y a beaucoup d'appels qui signalent pas sûr, et vous pouvez finir par se tirer une balle dans le pied si vous faites, par exemple, un appel à malloc à l'intérieur malloc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top