Question

J'ai un programme qui effectue délibérément une division par zéro (et stocke le résultat dans une variable volatile) afin de s'arrêter dans certaines circonstances. Toutefois, j'aimerais pouvoir désactiver cette interruption sans changer la macro qui effectue la division par zéro.

Y a-t-il un moyen de l'ignorer?

J'ai essayé d'utiliser

#include <signal.h>
...
int main(void) {
  signal(SIGFPE, SIG_IGN);
  ...
}

mais il meurt toujours avec le message "Exception à virgule flottante (noyau vidé)".

Je n'utilise pas réellement la valeur, donc je ne me soucie pas vraiment de ce qui est assigné à la variable; 0, aléatoire, indéfini ...

EDIT: Je sais que ce n’est pas le plus portable, mais il est destiné à un périphérique intégré fonctionnant sur de nombreux systèmes d’exploitation. L'action d'arrêt par défaut consiste à diviser par zéro; d'autres plates-formes nécessitent différentes astuces pour forcer un redémarrage induit par un chien de garde (comme une boucle infinie avec des interruptions désactivées). Pour un environnement de test PC (linux), je voulais désactiver l’arrêt sur division par zéro sans me baser sur des choses comme assert.

Était-ce utile?

La solution

Pourquoi voudriez-vous délibérément diviser par zéro pour arrêter? Ne pourriez-vous pas exit (-1) ou un équivalent?

Surtout si vous n'avez pas besoin du résultat de la division par 0, cela n'a aucun sens.

Autres conseils

D'abord, vous devriez utiliser sigaction (2) au lieu du signal () obsolète () .

Deuxièmement, utiliser SIGFPE pour mettre fin au programme est manifestement absurde, car vous devriez émettre un signal tel que SIGTERM ou SIGUSR1 au lieu de truquer sur un autre signal pour son effet secondaire et sans tenir compte de sa valeur sémantique. Et plus précisément, la page de manuel de sigaction (2) contient une section NOTES avec un texte de présentation relatif à SIGFPE qui indique une ou deux façons dont votre utilisation envisagée est rompue.

Ce que vous devriez faire est que soulève (3) un signal lorsque vous souhaitez terminer. Ensuite, utilisez le champ sa_handler de la structure sigaction pour indiquer si vous souhaitez ignorer ( SIG_IGN ) ou terminer ( SIG_DFL ) sur ce signal.

int main(void) {
  struct sigaction my_action;

  my_action.sa_handler = SIG_IGN;
  my_action.sa_flags = SA_RESTART;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1);  /* Ignored */

  my_action.sa_handler = SIG_DFL;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1); /* Terminates */

  return 0;
}

Cela dit, je ne vois pas pourquoi vous utiliseriez des signaux au lieu d'un simple exit () .

Vérifiez la valeur de retour de

signal(SIGFPE, SIG_IGN);

Si vous obtenez SIG_ERR , vérifiez la valeur de errno pour déterminer ce qui ne va pas. C’est tout ce que vous pouvez faire de façon portable.

Je sais que vous ne voulez pas changer la division par zéro, mais c'est non portable et contre-intuitif. Vous voulez effectuer un corump si une condition survient, mais être capable de désactiver ce comportement sans modifier le code? Utilisez assert et NDEBUG .

Ceci n'est pas portable, mais sur x86, vous pouvez contrôler le FPU:

Utilisation de gcc sous Linux (je suis sûr que d'autres compilateurs disposent d'installations similaires):

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

La valeur par défaut de _FPU_DEFAULT étant définie sur _FPU_MASK_ZM (ZM correspond à Zero-Divide-Mask).

void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);

Pourriez-vous provoquer la sortie du programme avec une expression moins artificielle? Par exemple:

#include <signal.h>

#ifdef DEBUG
#define DIE_HERE raise(SIGFPE)
#else
#define DIE_HERE
#endif

J'hésiterais à remplacer le comportement par défaut, de peur qu'une autre partie de votre programme divise par zéro involontairement. Sinon, si vous le forcez à quitter de cette manière afin d'obtenir un vidage mémoire, vous pouvez envisager d'utiliser des points d'arrêt dans un débogueur. Ou, si vous êtes sur un système avec le débogueur gdb, l’utilitaire gcore peut être utile.

Si vous avez le contrôle sur le code bloquant, je vous recommande également de changer le code pour qu'il meurt d'une autre manière. Sinon, vous pouvez essayer d'installer un gestionnaire de signal vide (c'est-à-dire utiliser signal (SIGFPE, & amp; EmptyFunction )), mais vous vous basez toujours sur un comportement indéfini. Il n'y a donc aucune garantie. cela fonctionnera toujours sur d'autres systèmes, ou d'autres versions du noyau ou de la bibliothèque C.

Si vous omettez le code, alors je vous recommanderais également de changer le code pour qu’il meure d’une autre manière. Si vous ne le faites pas, vous pouvez essayer d’installer un

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