- Exclure Rust du simple fait de l’existence de
unsafeet considérer Fil-C comme seul sûr passe à côté du champ réel d’application des logiciels et des compromis techniques - Fil-C transforme les accès mémoire invalides en panique dans les programmes C/C++, mais au prix d’une incompatibilité ABI, de ralentissements pouvant aller jusqu’à plusieurs fois dans certains cas, et de l’introduction d’un GC
- Dans Android, avec environ 5 millions de lignes de code Rust, un seul cas potentiel de vulnérabilité de sûreté mémoire corrigé avant la sortie a été trouvé, soit une estimation de 0,2 cas par million de lignes, contre environ 1 000 pour les anciennes données en C/C++
- Il n’est pas nécessaire de choisir entre une technologie qui bloque 99,9 % des problèmes dans tous les programmes et une autre qui en bloque 100 % dans 90 % des programmes ; pour les logiciels qui acceptent mal les contraintes de Fil-C, des alternatives comme Rust sont adaptées
- La sûreté mémoire doit être évaluée avec les performances, l’ABI, le GC et la prévention des courses de données ; si l’on critique Rust comme insuffisant, il faut au moins appliquer le même critère au C/C++ classique et à Zig hors Fil-C
Rust et le modèle de responsabilité des langages systèmes traditionnels
- Le débat sur la sûreté mémoire dans les langages de programmation système sans GC s’est surtout articulé autour de la différence de modèle de responsabilité entre Rust et C/C++/Zig
- Rust cherche à empêcher la compilation de programmes susceptibles de provoquer des problèmes de sûreté mémoire, au prix de rejeter aussi certains programmes qui pourraient pourtant être sûrs
unsafeest une porte de sortie qui permet de contourner certaines garanties, par exemple pour déréférencer des pointeurs bruts- Les langages de la famille C confient l’essentiel des garanties de sûreté mémoire au programmeur
- Même s’il existe des différences de niveau de support selon les langages, comme le RAII et les smart pointers en C++, ou
deferen Zig, ils ne bloquent pas par principe les accès mémoire invalides eux-mêmes
L’option supplémentaire apportée par Fil-C
- Fil-C propose une nouvelle approche pour exécuter du code C et C++ en sûreté mémoire
- Lorsqu’un accès mémoire invalide survient, comme un accès hors limites ou un use-after-free, il déclenche une panique
- Il combine un GC et InvisiCaps, qui suit la mémoire accessible par les pointeurs
- Un nouveau mode de compilation inspiré de Fil-C a aussi été proposé pour Zig
- Si certains projets C/C++ populaires proposaient des releases compilées avec Fil-C, cela pourrait offrir une option supplémentaire pour réduire les vulnérabilités de sûreté mémoire
Le critère selon lequel Rust ne serait pas sûr
- Le développeur de Fil-C affirme sur Twitter que Rust n’est pas un langage sûr du point de vue mémoire, au motif que
unsafepermet de contourner certaines garanties - Le développeur de Zig Andrew Kelley a lui aussi qualifié, dans le titre d’une issue liée, un mode inspiré de Fil-C de mode de compilation “réellement memory-safe, contrairement à Rust”
- Certaines discussions vont jusqu’à exiger que les utilisateurs de Rust, s’ils se soucient vraiment de sûreté mémoire, abandonnent Rust et fassent la promotion de Fil-C, jugé plus sûr
- Ce critère compare Rust et Fil-C sans tenir compte du coût concret de Fil-C et adopte une posture proche des critiques accusant parfois la communauté Rust de fanatisme
Les contraintes d’application de Fil-C
- Fil-C n’est pas un remplaçant drop-in sans coût
- Il n’est pas compatible au niveau ABI avec les programmes compilés sans Fil-C
- Il peut être plusieurs fois plus lent dans certaines situations
- Il introduit un GC
- Pour des programmes comme de petits utilitaires, où la baisse de performance est peu perceptible ou où le lien dynamique n’est pas nécessaire, ces contraintes peuvent ne pas être décisives
- À l’inverse, de nombreux projets populaires ne peuvent pas accepter un GC ni une incompatibilité ABI, et les programmes auxquels Fil-C, dans sa forme actuelle, s’applique mal sont souvent bien adaptés à Rust
Les données réelles sur les vulnérabilités dans le code Rust
- Il existe encore peu de données pour juger la sécurité réelle de Rust, mais on n’a pas observé beaucoup de vulnérabilités de sûreté mémoire exploitables dans des logiciels Rust
- Dans les plus de 5 millions de lignes de code Rust d’Android, un seul cas potentiel de vulnérabilité de sûreté mémoire a été découvert, puis corrigé avant la sortie
- La densité estimée est de 0,2 cas par million de lignes
- Les anciennes données C/C++ d’Android étaient d’environ 1 000 cas par million de lignes
- La densité du code Rust est donc suivie à un niveau plus de 1 000 fois inférieur à celui du C/C++
- Les chiffres peuvent varier selon les projets, mais ils appuient l’idée qu’en environnement réel, Rust réduit fortement le risque d’introduire des problèmes de sûreté mémoire
Pourquoi il n’est pas nécessaire de n’en choisir qu’un seul
- L’exemple hypothétique d’un choix entre une technologie qui bloque 99,9 % des problèmes dans tous les programmes et une autre qui en bloque 100 % dans 90 % des programmes montre que le périmètre d’application comme le niveau de prévention comptent tous deux
- Même si les proportions exactes sont inconnues, il n’est pas nécessaire de choisir un seul des deux approches
- Les projets C/C++/Zig capables d’accepter ces compromis peuvent proposer des binaires Fil-C
- Les logiciels qui ne peuvent pas utiliser Fil-C peuvent être écrits dans des langages qui éliminent totalement ou en grande partie le risque de vulnérabilités de sûreté mémoire
Pourquoi choisir Rust même si l’on peut utiliser un GC
- Il reste légitime de choisir Rust même s’il existe des options à GC comme Go ou Fil-C
- Les programmes pouvant être écrits dans un langage à GC n’ont souvent pas besoin de
unsafe, tandis que ceux qui ont besoin deunsafene peuvent souvent pas utiliser de GC - On peut juger plus importantes que ce faible risque de sûreté mémoire d’autres garanties et fonctionnalités du langage, comme la prévention des courses de données
- Fil-C transforme les vulnérabilités de sûreté mémoire du C/C++ existant en crashs
- C’est préférable à une vulnérabilité de sécurité, mais si la densité historique d’environ 1 000 cas par million de lignes reste la même, il restera beaucoup de crashs à corriger
- Par le passé, certaines vulnérabilités de sécurité reposaient justement sur la capacité d’un attaquant à faire planter un programme
Un critère cohérent de sûreté mémoire
- Si même les 0,2 cas par million de lignes de Rust sont inacceptables, alors il faut appliquer une critique équivalente ou plus stricte au C/C++ classique et à Zig hors Fil-C
- Tolérer des alternatives moins sûres que Rust tout en excluant Rust uniquement à cause de
unsaferevient à appliquer de manière incohérente un absolutisme de la sûreté mémoire
1 commentaires
Avis sur Lobste.rs
Le propos d’Andrew Kelly, que l’OP semble avoir mal pris, est que Zig peut compiler, y compris l’ensemble des dépendances C/C++, en exécutable entièrement memory-safe, sans échappatoire, avec un coût en performances d’environ 1 à 6× selon la fréquence du suivi des pointeurs
L’auteur y voit une attaque contre Rust et finit par attaquer Zig, mais Fil-C et le nouveau mode de build de Zig sont des contributions positives à l’écosystème, offrant des choix de conception et des compromis différents de Rust
J’interprète aussi cela comme signifiant qu’en suivant la programmation orientée données privilégiée par l’équipe Zig, on peut ramener le coût de performance près de 1×
Ce n’est pas absurde d’y voir une provocation inutile, et Andrew a ensuite remplacé le titre par quelque chose de moins agressif
À l’inverse de d’habitude, quand une légère moquerie du type « votre langage n’est pas memory-safe » a été dirigée vers Rust, l’ampleur de la réaction des développeurs Rust a été notable
J’aime beaucoup Rust moi aussi, mais il faut le prendre avec équité
D’ailleurs, le C formellement vérifié de seL4 est encore plus sûr
Zig a pour atouts de faciliter une terminaison correcte en cas d’échec d’allocation mémoire et de compiler rapidement
Je ne sais pas si Fil-C est plus memory-safe que Rust, mais pour mes usages, le garbage collector et l’incompatibilité avec l’ABI C sont des obstacles décisifs
On peut éviter les race conditions en restant monothread et obtenir la memory safety avec un garbage collector, mais j’aime que Rust fournisse les deux sans ces compromis
Comme j’accorde énormément d’importance à la memory safety, Fil-C et l’implémentation de l’ABI Fil-C dans Zig sont des choix naturels
Un projet Rust avec des dépendances C voit ses garanties de sûreté affaiblies, et n’utiliser que du Rust pur est possible mais peu pratique
Rust devrait lui aussi implémenter l’ABI Fil-C pour pouvoir construire en toute sécurité des dépendances C et les lier à Rust, et je ne vois pas pourquoi ce serait polémique
Si on implémente quelque chose de similaire, j’aimerais que ce soit un outil auxiliaire servant seulement à améliorer le code FFI en build de debug
Avoir un garbage collector et vérifier toutes les opérations à l’exécution ne convient pas à tous les usages
Avant de réduire Fil-C à un simple utilitaire, il faut voir la présentation de Fil-C à la conférence Software Should Work
L’intervenant a fait sa présentation sur un portable Linux dont tout l’espace utilisateur, jusqu’à OpenOffice Impress, tournait en Fil-C
Ce ne sera sans doute pas adapté à certains programmes C/C++, mais cela ne ressemble pas à une technologie gadget autant que l’auteur le pense
Venant de Python, la memory safety était pour moi un prérequis, et j’ai choisi Rust pour trois raisons
Premièrement, son système de types puissant permet d’assurer la correction à la compilation, et la memory safety obtenue avec
#![forbid(unsafe_code)]et l’audit des dépendances via cargo-geiger est l’expression la moins intéressante de celaDeuxièmement, il offre un écosystème qui facilite l’écriture sûre d’un code qu’on peut ensuite partager entre plusieurs langages et environnements d’exécution
Troisièmement, il a du sucre syntaxique qui rend agréable l’écriture de code de haut niveau, comme
try!(x)à l’époqueZig et Fil-C ne semblent pas offrir cette capacité à faire attraper les erreurs logiques par le compilateur en encodant dans le système de types des invariants via le pattern typestate ou les newtypes
L’incompatibilité ABI de Fil-C pose aussi problème pour écrire des modules compilés de façon sûre pour des runtimes existants, comme le CPython d’un hébergement web mutualisé
comptimeest plus expressif que RustIl y a des compromis en temps de compilation, en verbosité, et le fait que la majeure partie de l’écosystème ne pousse pas jusque-là, mais c’est réellement possible et assez amusant
Je me demande pourquoi une technologie comme Fil-C n’est pas apparue il y a 20 ans
Mais personne ne voulait en payer le prix en CPU ou en mémoire, autrement dit en coût
Entre 2004 et 2018, l’idée existait, mais il pensait que le concept même de C memory-safe était absurde ; entre 2018 et 2023, il a changé d’avis, mais sans trouver comment atteindre une compatibilité extrême
Le Fil-C du début, entre 2023 et 2024, avait une compatibilité et des performances bien inférieures ; à la fin 2024, la percée d’InvisiCaps a permis d’obtenir le haut niveau actuel de compatibilité et des performances correctes
Ce qui lui a fait changer d’avis vers 2018, c’est l’observation que les variantes de C utilisées sur GPU sont une forme simple de C memory-safe
Si on interprète de la façon la plus charitable l’idée selon laquelle « si le camp Rust se souciait vraiment de memory safety, il devrait soutenir Fil-C, plus sûr, et abandonner Rust », cela signifie qu’à présent que Fil-C existe, il faudrait cesser les efforts pour réécrire le monde en Rust, revenir à C/C++ et conserver l’écosystème unifié de bibliothèques d’autrefois
Même si les bibliothèques Rust peuvent être utilisées depuis C/C++, certains développeurs ne le souhaitent pas, donc si les utilisateurs de Rust reconnaissaient qu’il existe une meilleure solution et abandonnaient, la fragmentation disparaîtrait, selon cette logique
Mais Fil-C implique des compromis que Rust n’a pas, notamment un garbage collector et un support limité à x86-64 Linux
Au-delà de la memory safety, Cargo et l’absence d’espace de noms global sont des raisons majeures d’utiliser Rust, et il est regrettable que les divisions entre camps de langage soient mêlées à une guerre culturelle plus large
On veut juste construire des bibliothèques que tout le monde aura envie d’utiliser
Certains développeurs C peuvent ne pas vouloir de bibliothèques C++, et avec Zig et Odin en plus, la fragmentation restera même si Rust disparaît
Je me demande si Rust crée vraiment une fragmentation d’une nature particulière
comptimeRust encode davantage de contraintes, ce qui en fait un langage source idéal