Un atelier Rust · Édition d'ApprentissageA Rust Workshop · Learning Edition

unsafe & FFI, ou le dernier recours encapsulé unsafe & FFI, or the encapsulated last resort

unsafe ne désactive pas les règles de Rust : il transfère leur preuve du compilateur vers toi. Le dernier recours, encapsulé derrière une API sûre — pas le réflexe pour contourner un combat de borrow checker. unsafe does not disable Rust's rules: it transfers their proof from the compiler to you. The last resort, encapsulated behind a safe API — not the reflex to dodge a borrow checker fight.

AudienceAudience
Dev ayant parcouru la série — possession, types, concurrence (Vol 1–8) Dev who's gone through the series — ownership, types, concurrency (Vol 1–8)
Format
Self-paced
ChapitresChapters
5
Date
Juin 2026 Jun 2026
≈ 18 min ●●●● CoûtunsafeFFI

Chapitre 1 en accès libre — la suite (ch. 2 à 5) est réservée. Chapter 1 free to read — the rest (ch. 2–5) is members-only.

01CadrageFraming3 min

unsafe ne désactive aucune règle : il transfère leur preuve du compilateur vers toi.unsafe disables no rule: it transfers their proof from the compiler to you.

Voici le dernier numéro de la série, et son sujet est l'unique porte de sortie du système de preuve. Pendant huit volumes, on a laissé le compilateur prouver la sûreté : la possession, les durées de vie, l'absence de course. unsafe est la porte par laquelle on en sort. Mais attention au contre-sens le plus répandu : unsafe ne « désactive » pas les règles de Rust. Il fait une seule chose — autoriser cinq opérations que le compilateur ne sait pas vérifier (déréférencer un pointeur brut, appeler une fonction unsafe, toucher un static mutable, implémenter un trait unsafe, lire un champ d'union) — à une condition : que ce soit toi, désormais, qui garantisses les invariants que le compilateur vérifiait à ta place. Le contrat qu'il tenait, tu le signes. Le tenir, et tout va bien ; le rompre, et c'est l'undefined behavior — le bug que rien ne rattrape.Here's the series' final issue, and its subject is the single exit from the proof system. For eight volumes, we let the compiler prove safety: ownership, lifetimes, the absence of races. unsafe is the door you leave through. But beware the most widespread misreading: unsafe does not 'disable' Rust's rules. It does one thing — allow five operations the compiler can't verify (dereference a raw pointer, call an unsafe function, touch a mutable static, implement an unsafe trait, read a union field) — on one condition: that it's now you who guarantees the invariants the compiler checked in your place. The contract it held, you sign. Uphold it, and all is well; break it, and it's undefined behavior — the bug nothing catches.

La preuve change de main — du compilateur vers toiThe proof changes hands — from the compiler to you
safe Rustsafe Rust
le COMPILATEUR prouvethe COMPILER proves
possession, lifetimes, aliasing — vérifiésownership, lifetimes, aliasing — checked
unsafe {}la preuve ▸the proof ▸change de garantchanges guarantor
bloc unsafeunsafe block
TOI qui prouvesYOU prove
mêmes invariants — garantis à la mainsame invariants — guaranteed by hand
Une promesse que le compilateur ne vérifie plusA promise the compiler no longer checks
let x = 42;
let ptr = &x as *const i32;     // un pointeur brut : le CRÉER est sûr…

let valeur = unsafe { *ptr };   // …le DÉRÉFÉRENCER ne l'est pas. unsafe = « je PROMETS que
                                //   ce pointeur est valide, aligné, et pointe une donnée vivante ».
// le compilateur ne vérifie plus cette promesse : c'est TOI qui réponds de sa véracité.
// la tenir → tout va bien. la rompre → undefined behavior, le pire des bugs.

Créer un pointeur brut est sûr — ce n'est qu'un nombre. Le déréférencer ne l'est pas : rien ne garantit qu'il pointe encore vers une donnée vivante, valide, bien alignée. En safe Rust, c'est exactement ce qu'une référence & prouve, et que le compilateur impose. Dans le bloc unsafe, il te laisse déréférencer — mais la garantie, c'est toi qui la portes. unsafe n'est donc pas « moins de règles » ; c'est les mêmes règles, avec un autre garant. Et ce garant, faillible, c'est l'humain.Creating a raw pointer is safe — it's just a number. Dereferencing it isn't: nothing guarantees it still points to live, valid, well-aligned data. In safe Rust, that's exactly what a & reference proves, and what the compiler enforces. In the unsafe block, it lets you dereference — but the guarantee, you carry. unsafe isn't 'fewer rules'; it's the same rules, with another guarantor. And that guarantor, fallible, is the human.

Le réflexe du numéroThe issue's reflex

« Cet unsafe est-il encapsulé derrière une API sûre dont je peux prouver les invariants — ou éparpillé parce que je n'ai pas compris l'erreur ? » C'est la question qui sépare le bon usage du mauvais. Le bon unsafe est rare, localisé, justifié par un commentaire // SAFETY:, et enfermé derrière une fonction sûre. Le mauvais est diffus, posé pour faire taire le compilateur, et fait peser sur tout le programme un risque d'UB qu'aucun test ne révèle.'Is this unsafe encapsulated behind a safe API whose invariants I can prove — or scattered because I didn't understand the error?' That's the question separating good use from bad. Good unsafe is rare, localized, justified by a // SAFETY: comment, and locked behind a safe function. Bad unsafe is diffuse, dropped to silence the compiler, and makes the whole program carry a risk of UB no test reveals.

UB : pas un crash, une trahison.UB: not a crash, a betrayal.

L'undefined behavior n'est pas « le programme plante ». C'est pire et plus sournois. Le compilateur optimise en supposant que l'UB n'arrive jamais — c'est une hypothèse sur laquelle il bâtit tout son raisonnement. Si tu violes cette hypothèse, il a déjà compilé du code qui en dépend : le résultat peut être un crash, mais aussi une corruption silencieuse, une faille de sécurité, un comportement qui change selon le niveau d'optimisation ou la version du compilateur. L'UB n'est pas un bug local : c'est l'effondrement de toutes les garanties, partout, de façon imprévisible. D'où la gravité du contrat qu'unsafe te fait signer.Undefined behavior isn't 'the program crashes'. It's worse and more insidious. The compiler optimizes assuming UB never happens — it's an assumption on which it builds all its reasoning. If you violate that assumption, it has already compiled code depending on it: the result can be a crash, but also silent corruption, a security hole, a behavior that changes with the optimization level or the compiler version. UB isn't a local bug: it's the collapse of all guarantees, everywhere, unpredictably. Hence the gravity of the contract unsafe makes you sign.

🔒

La suite est réservée The rest is members-only

Le premier numéro est libre. Débloque tout The Rust Loop — tous les volumes, à vie — pour 5 €, paiement unique. The first issue is free. Unlock all of The Rust Loop — every volume, forever — for €5, one-time.

Retour au kiosqueBack to newsstand