Pourquoi?Il est interdit d'appeler longjmp() depuis un gestionnaire de signal.
PS: chez nous on dit pas de gros mots.
Ce qui me g�ne avec �a, c'est que mon prof de C m'a dit que "au point o� �a a plant�" signifiait "juste avant le plantage", et que la prochaine instruction allait re-planter (ce qui rend donc l'attrapage du signal inutile si l'on ne peut pas faire de longjump).
Ton UB, vient-il du texte C99 ou du texte POSIX? Si c'est le premier cas, il est possible que �a ne soit pas ind�fini sous POSIX...
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Pourquoi? je ne vois pas au contraire l'utilit� de faire un longjmp() dans un gestionnaire de signal, en revanche il y a d'autres choses � faire (setter une variable, loguer).
C'est la m�me chose dans POSIX:
The following table defines a set of functions that shall be either reentrant or non-interruptible by signals and shall be async-signal-safe. Therefore applications may invoke them, without restriction, from signal-catching functions:
_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execle()
execve()
fchmod()
fchown()
fcntl()
fdatasync()
fork()
fpathconf()
fstat()
fsync()
ftruncate()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
kill()
link()
listen()
lseek()
lstat()
mkdir()
mkfifo()
open()
pathconf()
pause()
pipe()
poll()
posix_trace_event()
pselect()
raise()
read()
readlink()
recv()
recvfrom()
recvmsg()
rename()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
sleep()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sockatmark()
socket()
socketpair()
stat()
symlink()
sysconf()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
utime()
wait()
waitpid()
write()
All functions not in the above table are considered to be unsafe with respect to signals. In the presence of signals, all functions defined by this volume of IEEE Std 1003.1-2001 shall behave as defined when called from or interrupted by a signal-catching function, with a single exception: when a signal interrupts an unsafe function and the signal-catching function calls an unsafe function, the behavior is undefined.
Utilit� simple: Faire retourner au setjmp() une variable qui dit "ne fais pas �a".
Exemple caricatural (de m�moire, tir� d'une d�monstration du prof de C)
Bref, utiliser longjmp() dans un gestionnaire de signal permet de le traiter comme un gestionnaire d'exception C++, au lieu d'un truc qui dit "on loggue avant que �a ait le temps de crasher" (je rappelle que le prof en question avait dit que le retour se faisait juste avant le plantage, donc on aurait eu un nouveau SIGDIV sans le longjmp).
Code C : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 jmp_buf buf; void handler(int sig) { (void)sig; longjmp(&buf, 1); } int main(void) { for(;;) { int a, b; printf("Entrer a et b, -1 pour quitter: ") /* Pour simplifier, on suppose ici que scanf() réussit toujours */ scanf("%d %d", &a, &b); { int jmpRet = setjmp(&buf); signal(SIGDIV, handler); if(jmpRet == 0) { int res = a/b; printf("Resultat: %d\n", res) } else printf("error"); } } }
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
J'ajouterai que tu n'as pa le droit de stocker le retour de setjmp() dans une variable.
L�, j'ai du mal � voir pourquoi. S'il y a une race condition, elle sera l� qu'on le fasse ou non, non?
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
C'est dans la norme (C89/C99/POSIX):
4 Environmental limits
An invocation of the setjmp macro shall appear only in one of the following contexts:
�the entire controlling expression of a selection or iteration statement;
�one operand of a relational or equality operator with the other operand an integer constant expression, with the resulting expression being the entire controlling expression of a selection or iteration statement;
�the operand of a unary ! operator with the resulting expression being the entire controlling expression of a selection or iteration statement; or
�the entire expression of an expression statement (possibly cast to void).
5 If the invocation appears in any other context, the behavior is undefined.
Eh bien cette partie-l�, je peux la corriger:
Mais si on interdit d'utiliser longjmp() et si mon prof disait vrai (ce qui est loin d'�tre prouv�), attraper un signal comme SIGDIV ou SIGSEGV ne sert � rien puisqu'il est impossible de "sauver" le processus: On peut seulement loguer l'in�vitable...
Code C : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 jmp_buf buf; void handler(int sig) { (void)sig; longjmp(&buf, 1); } int main(void) { for(;;) { int a, b; printf("Entrer a et b, -1 pour quitter: ") /* Pour simplifier, on suppose ici que scanf() réussit toujours */ scanf("%d %d", &a, &b); if(!setjmp(&buf)) { void (*psig)(int); psig = signal(SIGDIV, handler); { int res = a/b; printf("Resultat: %d\n", res) } signal(SIGDIV, psig); } else printf("error"); } }
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
D�sol� de t'enlever des illusions, mais ton prof �tait vraiment nul sur ce coup...
C'est recommand� partout..
Et si (comme on le fait quand m�me relativement souvent) on viole un tantinet la recommandation et on met du code ou des appels de fonctions dans un handler, pourquoi se servir de setjmp (bas niveau et peu clair) alors qu'on a � sa disposition de quoi appeler directement une fonction ???
Absolument...
Dans ce cas, absolument, �a ne sert � rien d'autre...
Il y a un certain nombre de handlers/signaux qui peuvent permettre de s'en sortir, mais il y a un certains nombres de signaux pour lesquels il n'y a aucune utilit� autre...
Si je prends ton exemple, il est bien plus clair de faire :
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11 void crash ( int sig ) { fprintf(stderr, "Le programme a crashé à cause d'une division par zéro (signal %d)\n",sig); } void handler(int sig) { crash(sig); }
Eh bien, il faut croire que mon prof avait raison, du moins en ce qui concerne Windows et Visual Studio:
Sous Visual, ce programme re-crashe imm�diatement apr�s le signal.
Code C : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 // TestSignal.c : Defines the entry point for the console application. // #include <stdio.h> #include <signal.h> #include <windows.h> typedef void (*SIGNAL_HANDLER)(int); void mysighandler(int sig) { OutputDebugStringA("Signal!\n"); /* Sans cette ligne, j'ai une unhandled exception juste après l'affichage de "Signal!" */ /* Avec la ligne, j'ai une boucle infinie */ signal(SIGSEGV, mysighandler); } int main(void) { int toto = 42; int *pTata = NULL; SIGNAL_HANDLER res = signal(SIGSEGV, mysighandler); if(res == SIG_ERR) { perror("signal"); } else { puts("Signal OK!"); puts("Attention..."); toto = *pTata; puts("Apres."); printf("Toto = %d\n", toto); } return 0; }
Il est donc impossible de "sauver" le programme d'un SIGSEGV.
setjmp() permet de remonter dans le flux "normal" du programme, ce qu'un appel de fonction ne permet pas.Et si (comme on le fait quand m�me relativement souvent) on viole un tantinet la recommandation et on met du code ou des appels de fonctions dans un handler, pourquoi se servir de setjmp (bas niveau et peu clair) alors qu'on a � sa disposition de quoi appeler directement une fonction ???
D'un autre c�t�, j'admets que reprendre le flux "normal" d'un programme qui fait une SIGSEGV n'est pas recommand�. Mais �a m'a quand m�me �vit� bien souvent de perdre du travail non-enregistr� dans Dev-C++...
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Ce raisonnement qui semble l�gitime � premi�re vue est erron�:
D�j�, en temps normal, il y a des restrictions sur ce que tu appelles le flux normal du programme, notamment, avec les variables locales non volatiles modifi�s entre l'appel � setjmp() et l'appel � longjmp(), leur valeur est ind�termin�
mais dans le cadre de la r�ception d'un signal, c'est encore pire, le fait de faire un longjmp() ne retire pas le cot� asynchrone de la r�ception du signal, si celui ci � �t� d�livr� pendant l'appel � une fonction non async signal safe, alors le comportement est ind�temin� (pensez � l�tat des variables statiques), et �tant donn� qu'on ne peut savoir ou l'on a �t� interrompu, il est impossible de reprendre sereinement le soit disant flux normal du programme. C'est bien pour cela que ces 2 fonctions ne font pas partie des fonctions qu'il est possible d'appeler � partir d'un gestionnaire de signal.All accessible objects have values, and all other components of the abstract machine
have state, as of the time the longjmp function was called, except that the values of
objects of automatic storage duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have volatile-qualified type
and have been changed between the setjmp invocation and longjmp call are
indeterminate.
Cordialement.
Oui, sous Windows, tu ne peux pas intercepter ce genre de signal (enfin, ce n'est pas vraiment un signal au sens Unix en fait). De m�moire, c'est pareil sur les processeurs SPARC (Solaris) avec le "Bus error".
A titre informatif, tenter d'intercepter ce genre de signal m'a toujours paru assez �trange comme id�e : ce genre d'erreur ne devrait jamais d�passer le stade des tests unitaires, et si c'est malgr� tout apr�s les tests basiques, tu as des cores pour savoir o� s'est produite l'erreur... Cela reste une erreur critique, souvent facile � trouver qui plus est, et bien trop "grave" pour envisager de continuer sereinement l'ex�cution du programme.
Mac LAK.
___________________________________________________
Ne prenez pas la vie trop au s�rieux, de toutes fa�ons, vous n'en sortirez pas vivant.
Sources et composants Delphi sur mon site, L'antre du Lak.
Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum ad�quat.
Rejoignez-nous sur : ► Serveur de fichiers [NAS] ► Le Tableau de bord projets ► Le groupe de travail ICMO
Je n'ai jamais dit "sereinement", mais sous un programme buggu� comme Dev-C++, �a permettait au moins d'enregistrer tes fichiers et quitter.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
non, c'est possible de l'intercepter sous Solaris:
Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 bash-2.03$ uname -a SunOS dadevsol28 5.8 Generic_108528-18 sun4u sparc SUNW,Sun-Fire-V240 bash-2.03$ cat main.c #include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #define MESSAGE "SIGBUS catched\n" static void signal_handler(int signo) { write(STDOUT_FILENO, MESSAGE, sizeof MESSAGE - 1); _exit(EXIT_FAILURE); } int main(void) { if(signal(SIGBUS, signal_handler) == SIG_ERR) { perror("signal"); } else { unsigned char buffer[2] = {0}; int n = *((int *)&buffer[1]); printf("%d\n", n); } return 0; } bash-2.03$ ./main SIGBUS catched bash-2.03$
Je crois que cela n'est pas ce que nous appelons "intercepter".
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Ceci est un tout autre probl�me, en fait : un probl�me de choix d'IDE / outil...
Le signal n'est pas intercept� ("catch�"), l� tu fais uniquement un affichage diff�rent par rapport � l'affichage standard d'un Bus Error. Tu ne peux pas reprendre l'ex�cution du programme o� il en �tait.
Mac LAK.
___________________________________________________
Ne prenez pas la vie trop au s�rieux, de toutes fa�ons, vous n'en sortirez pas vivant.
Sources et composants Delphi sur mon site, L'antre du Lak.
Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum ad�quat.
Rejoignez-nous sur : ► Serveur de fichiers [NAS] ► Le Tableau de bord projets ► Le groupe de travail ICMO
Bien que le Standard C et la MSDN n'emploi en aucun cas le terme "catched", la sp�cification POSIX elle, est claire � ce sujet, ce que j'ai fait est bien un catch du signal, que vous le vouliez ou non, le fait d'intercepter un signal ne se limite pas au fait de reprendre le programme au point ou il a �t� interrompu.
The behavior of a process is undefined after it returns normally from a signal-catching function
for a SIGBUS, SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(), sigqueue(),
or raise().
Si tu veux. En attendant, intercepter un signal juste pour r��crire diff�remment ce que l'OS aurait tr�s bien �crit tout seul, je n'en vois pas l'int�r�t pour ma part.
L'int�r�t est de pouvoir reprendre l'ex�cution normale au lieu de laisser le processus crever tout seul, ou �ventuellement de pouvoir effectuer une tentative (d�sesp�r�e ?) de fermeture "propre", mais si ce n'est pour aucune de ces raisons, c'est pour moi du code inutile.
Mac LAK.
___________________________________________________
Ne prenez pas la vie trop au s�rieux, de toutes fa�ons, vous n'en sortirez pas vivant.
Sources et composants Delphi sur mon site, L'antre du Lak.
Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum ad�quat.
Rejoignez-nous sur : ► Serveur de fichiers [NAS] ► Le Tableau de bord projets ► Le groupe de travail ICMO
Partager