Pourquoi avoir choisi d'intégrer Rust à Chromium ?
L'objectif de l'intégration de Rust dans Chromium est de fournir un moyen plus simple (pas d'IPC) et plus sûr (C++ moins complexe dans l'ensemble, pas de bogues de sécurité de la mémoire dans une sandbox) de satisfaire la règle des deux, afin d'accélérer le développement (moins de code à écrire, moins de documents de conception, moins d'examens de sécurité) et d'améliorer la sécurité (augmentation du nombre de lignes de code sans bogues de sécurité de la mémoire, diminution de la densité de bogues du code) de Chrome. De plus, la société est convaincue que nous pouvons utiliser des bibliothèques Rust tierces pour atteindre cet objectif.
Rust a été développé par Mozilla spécifiquement pour être utilisé dans l'écriture d'un navigateur, il est donc tout à fait approprié que Chromium commence enfin à s'appuyer sur cette technologie également. Merci Mozilla pour votre énorme contribution à l'industrie des logiciels de systèmes. Rust a été une preuve incroyable que nous devrions être en mesure d'attendre d'un langage qu'il offre la sécurité tout en étant performant.
Nous savons que C++ et Rust peuvent jouer ensemble de manière agréable, grâce à des outils comme cxx, autocxx bindgen, cbindgen, diplomat, et (expérimental) crubit. Cependant, il y a aussi des limites. Nous pouvons nous attendre à ce que la forme de ces limitations change avec le temps grâce à des outils nouveaux ou améliorés, mais les décisions et les descriptions ici sont basées sur l'état actuel de la technologie.
Comment Chromium prendra en charge l'utilisation de Rust
L'équipe chargée de la sécurité de Chrome a consacré du temps à étudier la manière dont nous devrions aborder l'utilisation de Rust parallèlement à notre code C++. Comprendre les implications du passage progressif à l'écriture de Rust au lieu de C++, même au milieu de notre pile logicielle. Quelles pourraient être les limites d'une interopérabilité sûre, simple et fiable.
Sur la base de nos recherches, nous avons abouti à deux résultats pour Chromium :
- L'interopérabilité ne sera prise en charge que dans une seule direction, de C++ à Rust, pour le moment. Chromium est écrit en C++, et la majorité des stackframes sont dans du code C++, de main() à exit(), c'est pourquoi nous avons choisi cette direction. En limitant l'interopérabilité à une seule direction, nous contrôlons la forme de l'arbre de dépendance. Rust ne peut pas dépendre de C++, il ne peut donc pas connaître les types et fonctions C++, sauf par injection de dépendances. De cette façon, Rust ne peut pas atterrir dans du code C++ arbitraire, seulement dans les fonctions passées par l'API depuis C++.
- Pour l'instant, nous ne prendrons en charge que les bibliothèques tierces. Les bibliothèques tierces sont écrites comme des composants autonomes, elles ne possèdent pas de connaissances implicites sur l'implémentation de Chromium. Cela signifie qu'elles ont des APIs plus simples et centrées sur leur seule tâche. Ou, en d'autres termes, elles ont généralement une interface étroite, sans graphes de pointeurs complexes et sans propriété partagée. Nous examinerons les bibliothèques que nous introduisons pour une utilisation en C++ afin de nous assurer qu'elles répondent à cette attente.
L'interopérabilité entre Rust et C++ dans Chromium
Nous avons observé que la plupart des histoires d'interopérabilité C/C++ et Rust réussies à ce jour ont été construites autour de l'interopérabilité par le biais d'API étroites (par exemple, les bibliothèques pour QUIC ou Bluetooth, les pilotes Linux) ou par le biais de composants clairement isolés (par exemple, IDLs, IPCs). Chrome est construit sur des API C++ fondamentales mais très larges, telles que la couche //content/public. Nous avons examiné ce que cela signifierait pour nous de construire des composants Rust contre ces types d'API. À un haut niveau, nous avons constaté que, parce que C++ et Rust jouent selon des règles différentes, les choses peuvent déraper très facilement.
Par exemple, Rust garantit la sécurité de la mémoire temporelle avec une analyse statique qui s'appuie sur deux entrées : les durées de vie (inférées ou explicitement écrites) et la mutabilité exclusive. Cette dernière est incompatible avec la façon dont la majorité du C++ de Chromium est écrit. Nous avons des pointeurs mutables redondants dans tout le système, et des pointeurs qui fournissent plusieurs chemins pour atteindre les pointeurs mutables. Nous avons des structures de données mutables cycliques. Ceci est particulièrement vrai dans notre processus de navigation, qui contient un système géant interconnecté de pointeurs (mutables). Si ces pointeurs C++ étaient également utilisés comme références Rust d'une manière complexe ou durable, il faudrait que nos auteurs C++ comprennent les règles d'aliasing de Rust et empêchent la possibilité de les violer, comme par exemple :
- Renvoyant deux fois le même pointeur mutable d'une fonction, où le premier peut encore être détenu.
- Passer des pointeurs qui se chevauchent, dont l'un est mutable dans Rust, de manière à ce qu'ils puissent être maintenus comme références en même temps.
- Muter un état qui est visible par Rust à travers une référence partagée ou mutable.
Sans outils d'interopérabilité fournissant un support via le compilateur et le système de types, les développeurs devraient comprendre toutes les hypothèses faites par le compilateur Rust, afin de ne pas les violer à partir de C++. Dans ce cadre, C++ ressemble beaucoup à unsafe Rust. Et si Rust non sécurisé est très coûteux pour un projet, son coût est géré en le maintenant encapsulé et au minimum possible. De la même manière, toute la complexité du C++ devrait être encapsulée dans du Rust sûr. Les API étroites conçues pour l'interopérabilité peuvent fournir une encapsulation similaire, et nous espérons que les outils d'interopérabilité pourront fournir une encapsulation d'une autre manière afin de permettre des API plus larges entre les langages.
Le résumé de haut niveau est que sans support supplémentaire d'outils interop :
- Le passage de pointeurs/références entre les langages est risqué.
- Des interfaces étroites entre les langages sont essentielles pour permettre d'écrire du code correctement.
Toute interopérabilité inter-langue entre du code arbitraire introduit des difficultés lorsque les concepts d'une langue ne se retrouvent pas dans l'autre. Pour les appels de Rust vers C++, la prise en charge des caractéristiques du langage comme les templates ou l'héritage peut être difficile pour un générateur de liaisons. Pour les appels du C++ vers le Rust, les macros proc et les traits sont des exemples qui présentent des difficultés similaires. Parfois, l'inadéquation de l'impédance représente des choix de conception intentionnels faits pour l'un ou l'autre langage, mais elle implique également des limites à la FFI (interopérabilité) entre les langages. Nous comptons sur les outils d'interopérabilité pour modéliser les idées de chaque langage de manière à ce qu'elles aient un sens pour l'autre, ou pour les interdire.
Accéder à l'écosystème Rust depuis Chromium
Ces défis représentent une opportunité, à la fois pour rendre l'interopérabilité plus facile et plus transparente, mais aussi pour accéder à un plus grand nombre de bibliothèques dans les deux langages. Google investit dans Crubit, une expérience visant à accroître la fidélité de l'interopérabilité entre C++ et Rust et à exprimer ou encapsuler les exigences de chaque langage dans l'autre.
L'écosystème Rust est incroyablement important, en particulier pour un projet open source axé sur la sécurité comme Chromium. L'écosystème est énorme (plus de 96 000 crates sur crates.io) et en pleine croissance, avec des investissements de l'industrie du développement de systèmes dans son ensemble, y compris Google. Chrome s'appuie fortement sur le code de tiers, et nous devons suivre les investissements de ces tiers. Il est essentiel que nous développions le support pour inclure Rust dans le projet Chromium.
Cette stratégie nous permettra d'établir des normes et de maintenir un niveau d'examen des API par le biais du processus tiers, tout en nous tournant vers l'avenir de l'interopérabilité en repoussant les limites de ce qui est possible et raisonnable de faire entre Rust et C++.
Autres contenus connexes
La non sécurité de la mémoire est un problème qui touche l'ensemble de l'industrie, et l'utilisation de Rust fait partie d'une stratégie visant à faire avancer les choses dans ce domaine. Récemment, Android et Apple ont chacun publié un excellent article de blog sur le sujet si vous souhaitez en savoir plus. Avec les millions de lignes de C++ de Chrome, nous continuons à travailler dur pour améliorer la sécurité de notre C++ également, grâce à des projets tels que MiraclePtr.
Source : Google
Et vous ?
Qu'en pensez-vous ?
Voir aussi :
C++ vs Rust*: une comparaison pratique de la vitesse de compilation et de test des deux langages de programmation, par Matthew Glazar, ingénieur en génie logiciel
GCC 13 prend désormais en charge Modula-2, le descendant de Pascal, il supporte également le langage Rust
Google fait état d'une baisse des vulnérabilités liées à la sécurité de la mémoire sur Android à mesure que l'utilisation de Rust augmente, elles seraient passées de 223 en 2019 à 85 en 2022
Google présente KataOS*: un OS open source pour le matériel embarqué axé sur la sécurité, avec seL4 comme micro-noyau et implémenté presque entièrement en Rust