Gestion des erreurs
Le type Result est la façon privilégiée en Rust pour décrire le type de retour
des fonctions dont le traitement peut échouer. Un objet Result doit être
testé et jamais ignoré.
Une crate PEUT implanter son propre type Error qui peut contenir toutes
les erreurs possibles. Des précautions supplémentaires DOIVENT être prises :
ce type DOIT être exception-safe (RFC 1236) et implémenter les traits
Error + Send + Sync + 'static ainsi que Display.
Des crates tierces peuvent être utilisées pour faciliter la gestion d'erreurs. La plupart (snafu, thiserror) proposent la création de types d'erreurs personnalisées qui implémentent les traits nécessaires et permettent l'encapsulation d'autres erreurs.
Une autre approche (notamment proposée dans anyhow) consiste à envelopper automatiquement les erreurs dans un seul type d'erreur universel. Une telle approche ne devrait pas être utilisée dans des bibliothèques ou des systèmes complexes parce qu'elle ne permet pas de fournir de contexte sur les erreurs ainsi initialement enveloppées, contrairement à la première approche.
Panics
La gestion explicite des erreurs (Result) doit être préférée à la place de
l'utilisation de la macro panic. La cause de l'erreur doit être rendue
disponible, et les erreurs trop génériques doivent être évitées.
Les crates fournissant des bibliothèques ne doivent pas utiliser de fonctions
ou d'instructions qui peuvent échouer en engendrant un panic.
Des motifs courants de code qui provoquent des panic sont :
- une utilisation de
unwrapou deexpect; - une utilisation de
assert; - un accès non vérifié à un tableau ;
- un dépassement d'entier (en mode debug) ;
- une division par zéro ;
- l'utilisation de
format!pour le formatage d'une chaîne de caractères.
Dans certains domaines critiques pour la sécurité, il est obligatoire de passer en mode sans échec dès qu'une erreur susceptible d'entraîner un comportement indéfini se produit. Dans ces situations, il est judicieux de déclencher délibérément un panic (ou d'interrompre l'exécution) puisque cela permet d'arrêter le système avant que des données ne soient corrompues, ou des défaillances liées à la sûreté ou la sécurité ne se propagent.
Pour un avion ou d'autres types de véhicule, ce comportement « fail-fast » peut être crucial : l'unité de contrôle principale doit s'arrêter immédiatement en cas de défaillance grave, puis transférer le contrôle à un sous-système redondant ou de secours capable d'arrêter le véhicule en toute sécurité ou de poursuivre son fonctionnement en mode réduit. Le redémarrage sur un système secondaire fiable garantit que le véhicule reste contrôlable, protège les occupants et évite les conséquences dangereuses qui pourraient résulter de la poursuite de l'exécution dans un état imprévisible.
Dans le cas où le développement n'est pas soumis à ce type de normes:
Les fonctions et instructions qui peuvent causer des panic à l'exécution
NE DOIVENT PAS être utilisées.
L'indice d'accès à un tableau DOIT être testé, ou la méthode get DOIT être
utilisée pour récupérer une Option.
FFI et panics
Lorsque du code Rust est appelé depuis du code écrit dans un autre langage (par exemple, du code C), le code Rust doit être écrit de sorte à ne jamais pouvoir paniquer. Dérouler (unwinding) depuis le code Rust vers le code étranger résulte en un comportement indéfini.
Le code Rust appelé depuis une FFI DOIT :
- soit être assuré de ne pas paniquer,
- soit utiliser
catch_unwindou le modulestd::panicpour s'assurer qu'il ne va pas abandonner un traitement puis laisser l'exécution retourner dans le langage appelant dans un état instable.
Il est porté à l'attention du développeur que catch_unwind ne va traiter que
les cas de panic, et va préserver les abandons de processus causés par
d'autres raisons.