SETJMP(3) Manuel du programmeur Linux SETJMP(3)

setjmp, sigsetjmp, longjmp, siglongjmp - Effectuer un saut non local

#include <setjmp.h>
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int sauvsigs);
noreturn void longjmp(jmp_buf env, int val);
noreturn void siglongjmp(sigjmp_buf env, int val);
Exigences de macros de test de fonctionnalités pour la glibc (consulter feature_test_macros(7)) :

setjmp() : consultez la section NOTES.

sigsetjmp():

_POSIX_C_SOURCE

Les fonctions décrites dans cette page sont utilisées pour effectuer des « sauts non locaux » : transfert de l'exécution d'une fonction à un emplacement prédéterminé d'une autre fonction. La fonction setjmp() établit de façon dynamique l'emplacement vers lequel le contrôle sera transféré ultérieurement et longjmp() se charge de transférer l'exécution.

La fonction setjmp() sauvegarde diverses informations concernant l'environnement de l'appelant (typiquement le pointeur de pile, le pointeur d'instruction, potentiellement les valeurs d'autres registres ainsi que le masque de signaux) dans le tampon env pour son utilisation ultérieure par longjmp(). Dans ce cas, setjmp() renvoie 0.

La fonction longjmp() utilise les informations stockées dans env pour transférer le contrôle à l'endroit où setjmp() fut appelé et restaurer (« rewind ») la pile à son état lors de l'appel à setjmp(). De plus, et en fonction de l'implémentation (voir NOTES), les valeurs d'autres registres et le masque de signaux du processus peuvent également être restaurées à leur état lors de l'appel à setjmp().

Après un appel réussi à longjmp(), l'exécution continue comme si setjmp() avait renvoyé une deuxième fois. Ce renvoi « factice » peut être distingué d'un vrai appel à setjmp() car il renvoie la valeur contenue dans val. Si le programmeur passe la valeur 0 à val par inadvertance, le renvoi « factice » retourne 1 à la place.

sigsetjmp() et siglongjmp() effectuent également des sauts non locaux mais permettent une gestion prévisible du masque de signaux du processus.

Si, et seulement si, l'argument sauvsigs passé à sigsetjmp() est non nul, le masque de signaux actuel du processus est sauvegardé dans env et sera rétabli lorsque siglongjmp() sera invoquée avec ce contexte env.

setjmp() et sigsetjmp() renvoient 0 lorsqu'elles sont appelées directement ; la valeur non nulle spécifiée dans val est renvoyée lors du renvoi « factice » qui se produit après un appel à longjmp() ou siglongjmp().

Les fonctions longjmp() et siglongjmp() ne renvoient pas.

Pour une explication des termes utilisés dans cette section, consulter attributes(7).
Interface Attribut Valeur
setjmp(), sigsetjmp() Sécurité des threads MT-Safe
longjmp(), siglongjmp() Sécurité des threads MT-Safe

setjmp(), longjmp() : POSIX.1-2001, POSIX.1-2008, C89, C99.

sigsetjmp(), siglongjmp() : POSIX.1-2001, POSIX.1-2008.

POSIX ne spécifie pas si setjmp() sauve le masque de signaux (pour être ensuite restauré lors de longjmp()). Sous System V, ce n'est pas le cas. Sous 4.3BSD, le masque sera sauvé et il y a une fonction _setjmp qui ne fait pas la copie. Le comportement sous Linux dépend de la version de la glibc ainsi que de la configuration des macros de test de fonctionnalités. Sous Linux avec glibc avant la version 2.19, setjmp() suit le comportement de System V par défaut, mais le comportement BSD est fourni si la macro de test de fonctionnalités _BSD_SOURCE est définie et qu’aucune des macros _POSIX_SOURCE, _POSIX_C_SOURCE, _XOPEN_SOURCE, _GNU_SOURCE ou _SVID_SOURCE n'est définie. Depuis glibc 2.19, <setjmp.h> n’expose que la version System V de setjmp(). Les programmes ayant besoin de le sémantique BSD devraient remplacer les appels de setjmp() par des appels de sigsetjmp() avec un argument sauvsigs non nul.

setjmp() et longjmp() peuvent être utiles pour gérer des erreurs dans des appels profondément imbriqués ou pour permettre à un gestionnaire de signal de passer le contrôle à un point précis du programme, plutôt que de renvoyer là où le gestionnaire a interrompu le programme principal. Dans ce dernier cas, si vous désirez sauvegarder et restaurer les masques de signaux de manière portable, utilisez sigsetjmp() et siglongjmp(). Consultez également la sous-section sur la lisibilité des programmes ci-dessous.

Le compilateur peut optimiser certaines variables dans des registres et longjmp() peut restaurer les valeurs d'autres registres en plus des pointeurs de pile et d'instruction. Par conséquent, les valeurs de variables automatiques ne sont pas spécifiées après un appel à longjmp() si elles satisfont à tous les critères suivants :

elles sont locales à la fonction qui a effectué l'appel correspondant à setjmp() ;
leur valeur est changée entre les appels à setjmp() et longjmp() ;
elles ne sont pas déclarées comme volatile.

Ces remarques s'appliquent aussi à siglongjmp().

Bien que la déclaration C traditionnelle « goto » puisse être exploitée, elle a pour bénéfice que les repères lexicaux (la déclaration de saut ainsi que l'étiquette cible) permettent au programmeur de percevoir de façon claire le flux de contrôle. Les sauts non locaux ne fournissent pas de tels repères : plusieurs appels à setjmp() peuvent utiliser la même variable jmp_buf de telle sorte que son contenu change au cours du déroulement de l'application. Par conséquent, le programmeur peut être astreint à une lecture détaillée du code afin de déterminer la cible dynamique d'un appel longjmp() particulier (pour rendre la tâche du programmeur plus simple, chaque appel à setjmp() devrait utiliser une variable jmp_buf unique).

De façon encore plus compliquée, les appels à setjmp() et longjmp() peuvent même provenir de modules de code source différents.

En résumé, les sauts non locaux peuvent rendre les programmes plus difficiles à comprendre et à maintenir, et une alternative devrait être utilisée lorsque c'est possible.

Si la fonction qui a appelé setjmp() renvoie avant que longjmp() ne soit appelée, le comportement n'est pas défini. Une sorte de chaos plus ou moins subtil en résulterait de façon certaine.

Si, dans un programme à plusieurs fils d'exécution, un appel à longjmp() utilise un tampon env initialisé préalablement par setjmp() dans un fil d'exécution différent, le comportement n'est pas défini.

Le Technical Corrigendum 2 de POSIX.1-2008 ajoute longjmp() et siglongjmp() à la liste des fonctions sûres vis-à-vis des signaux asynchrones. Cependant, la norme recommande de ne pas utiliser ces fonctions dans un gestionnaire de signal et indique ensuite que si ces fonctions sont appelées depuis un gestionnaire de signal qui a interrompu un appel à une fonction non sûre vis-à-vis des signaux asynchrones (ou similaire tels que les étapes équivalentes à exit(3) se produisant après un renvoi de l'appel initial main()), le comportement n'est pas défini si le programme fait par la suite un appel à une fonction non sûre vis-à-vis des signaux asynchrones. La seule façon d'éviter ce comportement non défini est de s'assurer de la chose suivante :

  • Après un saut non local depuis un gestionnaire de signal, le programme n'appelle pas de fonction non sûre vis-à-vis des signaux asynchrones et ne renvoie pas depuis l'appel initial à main().
  • Chaque signal dont le gestionnaire effectue un saut non local doit être bloqué lors de chaque appel à une fonction non sûre vis-à-vis des signaux asynchrones et aucune fonction non sûre vis-à-vis des signaux asynchrones n'est appelée après un renvoi depuis l'appel initial à main().

signal(7), signal-safety(7)

Cette page fait partie de la publication 5.11 du projet man-pages Linux. Une description du projet et des instructions pour signaler des anomalies et la dernière version de cette page, peuvent être trouvées à l'adresse https://www.kernel.org/doc/man-pages/.

La traduction française de cette page de manuel a été créée par Christophe Blaess https://www.blaess.fr/christophe/, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org> et Grégoire Scano <gregoire.scano@malloc.fr>

Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.

22 mars 2021