IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Google affirme qu'il est non seulement possible, mais aussi relativement facile de remplacer C/C++ par Rust dans les firmwares.
L'entreprise explique en quoi ce changement est avantageux

Le , par Stéphane le calme

12PARTAGES

12  0 
Dans le monde de la programmation, les langages C et C++ ont longtemps dominé le développement de firmware. Cependant, Google a récemment fait une déclaration audacieuse : remplacer ces langages par Rust serait non seulement possible, mais aussi relativement facile.

Pourquoi Rust ?

Rust est un langage de programmation qui a gagné en popularité grâce à ses caractéristiques de sécurité et de performance. Contrairement à C et C++, Rust offre une gestion de la mémoire plus sûre, réduisant ainsi les risques de bugs tels que les dépassements de tampon et les erreurs de libération de mémoire. Ces problèmes sont souvent à l’origine de vulnérabilités critiques dans les systèmes logiciels.

C'est d'ailleurs cet aspect sécuritaire que Google met en avant :

« Les microprogrammes servent d'interface entre le matériel et les logiciels de niveau supérieur. En raison de l'absence de mécanismes de sécurité standard dans les logiciels de niveau supérieur, les vulnérabilités du code des microprogrammes peuvent être dangereusement exploitées par des acteurs malveillants. Les téléphones modernes contiennent de nombreux coprocesseurs chargés de gérer diverses opérations, et chacun d'entre eux exécute son propre microprogramme. Souvent, les microprogrammes sont constitués d'importantes bases de code héritées du passé, écrites dans des langages peu sûrs pour la mémoire, tels que le C ou le C++. Le manque de sécurité de la mémoire est la cause principale des vulnérabilités d'Android, de Chrome et de nombreuses autres bases de code.

« Rust offre une alternative au C et au C++ sans risque pour la mémoire, avec des performances et une taille de code comparables. En outre, il prend en charge l'interopérabilité avec le C sans surcharge. L'équipe Android a déjà discuté de Rust pour les firmwares bare-metal et a développé une formation spécifique pour ce domaine ».

L'initiative de Google

Google a récemment réécrit le firmware des machines virtuelles protégées dans son Android Virtualization Framework en utilisant le langage de programmation Rust et souhaite que vous fassiez de même, à condition que vous vous occupiez de firmware.

Dans un article publié jeudi, les ingénieurs d'Android Ivan Lozano et Dominik Maier se penchent sur les détails techniques du remplacement du code C et C++ par le langage Rust. « Vous verrez à quel point il est facile de renforcer la sécurité avec des remplacements Rust, et nous démontrerons même comment la chaîne d'outils Rust peut gérer des cibles spécialisées bare-metal », ont déclaré Lozano et Maier.

Facile n'est pas un terme que l'on entend généralement à propos d'un langage de programmation connu pour sa courbe d'apprentissage abrupte. Il n'est pas non plus facile d'amener les développeurs C et C++ à voir le monde avec des lentilles teintées de Rust.

Quoiqu'il en soit, Google opte pour une adoption incrémentale :

« Notre approche incrémentale, qui se concentre sur le remplacement du nouveau code et du code existant le plus risqué (par exemple, le code qui traite des données externes non fiables), permet d'obtenir un maximum d'avantages en matière de sécurité avec un minimum d'efforts. Le simple fait d'écrire tout nouveau code en Rust réduit le nombre de nouvelles vulnérabilités et, au fil du temps, peut conduire à une réduction du nombre de vulnérabilités existantes.

« Vous pouvez remplacer une fonctionnalité C existante en écrivant un shim Rust fin qui fait la traduction entre une API Rust existante et l'API C attendue par la base de code. L'API C est reproduite et exportée par le shim pour que la base de code existante puisse s'y référer. Le shim sert d'enveloppe à l'API de la bibliothèque Rust, en faisant le lien entre l'API C existante et l'API Rust. Il s'agit d'une approche courante lors de la réécriture ou du remplacement de bibliothèques existantes par une alternative Rust ».

L'entreprise a également une vision quant au choix d'un composant à remplacer :

« Lors du choix d'un composant à remplacer, il convient de privilégier les composants autonomes qui font l'objet de tests rigoureux. Idéalement, la fonctionnalité du composant peut être fournie par une implémentation open-source facilement disponible qui supporte les environnements bare-metal.

« Les analyseurs qui gèrent des formats de données ou des protocoles standard et couramment utilisés (tels que XML ou DNS) sont de bons candidats initiaux. Cela garantit que l'effort initial se concentre sur les défis de l'intégration de Rust avec la base de code et le système de construction existants plutôt que sur les particularités d'un composant complexe et simplifie les tests. Cette approche facilite l'introduction ultérieure de Rust ».

Les défis de la transition

Malgré les avantages, la transition vers Rust n’est pas sans défis. L’un des principaux obstacles est la résistance des développeurs expérimentés en C et C++ à adopter un nouveau langage. De plus, Rust est connu pour sa courbe d’apprentissage abrupte, ce qui peut décourager certains programmeurs.

Il y a quelques jours, l'un des responsables du projet Rust pour Linux - créé pour intégrer le code Rust dans le noyau Linux basé sur le langage C - a démissionné, invoquant la résistance des développeurs du noyau Linux.

« Vous n'allez pas nous forcer à apprendre Rust », a déclaré un contributeur du noyau Linux lors d'une discussion animée au début de l'année à l'occasion d'une conférence.


Rendez-vous à 28:40

Néanmoins, Google encourage ceux qui le souhaitent à le faire. Citant le manque de mécanismes de sécurité de haut niveau dans les microprogrammes, qui sont souvent écrits dans des langages peu sûrs pour la mémoire tels que C ou C++, Lozano et Maier affirment que Rust offre un moyen d'éviter les bogues de sécurité de la mémoire tels que les débordements de mémoire tampon et l'utilisation après la libération qui représentent la majorité des vulnérabilités importantes dans les grandes bases de code.

« Rust offre une alternative au C et au C++ en matière de sécurité de la mémoire, avec des performances et une taille de code comparables », notent-ils. « En outre, il prend en charge l'interopérabilité avec le C sans surcoût.


Le gouvernement américain recommande Rust à la place de C/C++

Le gouvernement américain a récemment insisté sur ce thème, avec le soutien d'entreprises technologiques de premier plan et d'initiatives à but non lucratif visant à réécrire en Rust des projets et des composants open source essentiels. L'année dernière, l'Agence pour la cybersécurité et la sécurité des infrastructures (Cybersecurity & Infrastructure Security Agency) a recommandé aux fournisseurs de logiciels de « faire de la réduction et de l'élimination des vulnérabilités liées à la sécurité de la mémoire dans leurs gammes de produits un objectif d'entreprise de premier plan ».

Google était déjà convaincu par l'idée, ayant conclu que ses développeurs Rust sont deux fois plus productifs que ses ingénieurs C++.

« Nous reconnaissons le rôle essentiel de Rust dans la construction de logiciels sûrs et fiables à tous les niveaux de la pile », a déclaré Lars Bergstrom, directeur de l'ingénierie pour les langages de programmation Android chez Google et président du conseil d'administration de la Rust Foundation.

« Chez Google, nous augmentons l'utilisation de Rust dans Android, Chromium, et plus encore, afin de réduire les vulnérabilités liées à la sécurité de la mémoire. Nous sommes déterminés à collaborer avec l'écosystème Rust pour favoriser son adoption et fournir aux développeurs les ressources et la formation dont ils ont besoin pour réussir. Ce travail sur l'intégration de Rust dans les systèmes embarqués et les microprogrammes porte sur une autre partie essentielle de la pile ».

Conclusion

La déclaration de Google sur la facilité de remplacer C et C++ par Rust dans le firmware est une étape importante vers une programmation plus sûre et plus efficace. Bien que la transition puisse être difficile, les avantages à long terme en termes de sécurité et de productivité sont indéniables. Pour les entreprises technologiques, adopter Rust pourrait bien être la clé pour développer des logiciels plus robustes et sécurisés.

Source : Google

Et vous ?

Quels sont les avantages et les inconvénients que vous voyez dans l’utilisation de Rust par rapport à C et C++ ?
Pensez-vous que la courbe d’apprentissage de Rust est un obstacle majeur pour son adoption généralisée ? Pourquoi ou pourquoi pas ?
Comment évaluez-vous l’impact de la sécurité mémoire de Rust sur la qualité globale du code ?
Avez-vous des expériences personnelles ou des anecdotes sur la transition d’un projet de C/C++ à Rust ?
Quels types de projets ou d’industries bénéficieraient le plus de l’adoption de Rust selon vous ?
Comment les entreprises peuvent-elles encourager leurs développeurs à apprendre et à adopter Rust ?
Voyez-vous des domaines où C et C++ resteraient indispensables malgré les avantages de Rust ?
Quels outils ou ressources recommanderiez-vous pour apprendre Rust efficacement ?

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de NotABread
Membre régulier https://www.developpez.com
Le 10/09/2024 à 9:50
Citation Envoyé par 23JFK Voir le message
Il semble que Rust soit trop strict pour être viable dans la chaîne de développement d'une entreprise qui vise, entre autre, le profit. Le code permit par Rust est un sous-ensemble de tous les codes fiables et sécurisés possibles pour un problème donné. Les dev passeraient ainsi plus de temps à se battre avec le compilateur pour satisfaire à toutes les exigences de Rust qu'à écrire d'autres parties de code permettant de livrer dans les temps un produit "fini" (qui fait au moins ce pourquoi il a été prévu - Osef des bugs, les updates c'est fait pour les corriger) aux utilisateurs. Et de toute façon Rust ne permet pas de se prémunir contre les bugs/failles hardware comme celles qui ont affecté les processeurs Intel (DownFall etc...)
Je ne suis pas d'accord. Je trouve que le fait que le compilateur soit plus strict ne ralenti pas le développement, car entre le moment où tu ponds ton premier binaire et le moment où tu as un binaire près pour la release, et bien tu as des phases de test même minime. Donc certes, tu mettras plus de temps à satisfaire ce tyran de compilateur, mais tu gagneras en vas-et-viens entre la plateforme de test et ton PC car toutes les erreurs de manipulation de la mémoire sont éliminé avant même que les binaires soient mis sur la plateforme.

Après, Rust, c'est pas magique, tu auras toujours des problèmes de précision lié à la représentation numérique, dead lock et autre problème classique qui n'est pas en relation avec l'allocation, l'initialisation, la lecture, l'écriture et la libération de la mémoire. De plus, si la majorité du code doit être en unsafe, Rust ne serait pas adapté (pas assez de connaissance sur les microcontroleurs et firmware pour savoir dans quel scénario ça arrive)
3  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 13/09/2024 à 22:53
Citation Envoyé par 23JFK Voir le message
Ou que l'on obligé de faire de l'unsafe et l'unstable.
Et bien non! Il ne vous a pas échappé si vous êtes allés sur le Playground, que le code en question fonctionne dans une version stable de Rust:

Ce qui est nighty, c'est la librairie SIMD, pas les instructions machines répliquées dans le core Rust.

Pour ce qui est de l'unsafe, il est tout naturellement utilisé ici pour inclure du code machine, donc extérieur à Rust, tout comme on utilise de l'unsafe pour inclure une librairie C : cela sert à isoler les parties du code non contrôlées par la sémantique de sécurisation de Rust. Il s'agit pour le coup du contexte d'utilisation le plus simple de l'unsafe: délimiter le code externe. Pas de risque d'UB. Vous ne risqueriez donc pas d'y perdre des dents.
3  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 12/09/2024 à 11:15
Citation Envoyé par 23JFK Voir le message
Reste qu'apparemment, il n'est pas possible de tout faire en Rust et certain projet comme construire une librairie Rust semble carrément impossible, l'algorithme de la racine carré-inverse rapide ne semble pas non plus pouvoir être tolérée par le compilateur (spéculatif, je n'ai pas essayé ; mais étant donné qu'il faille jouer avec les différents motifs mémoire fonction du types des nombres, en Rust ça doit être un enfer) ; la compilation est affreusement lente quand il faut récupérer tous les paquets Cargo pour un gros projet. Franchement passé la hype, je ne vois pas comment Rust pourrait avoir une trajectoire différente d'Ocaml ou Haskell, c'est un truc d'université/laboratoire qui ne semble pas pouvoir s'adapter à la réalité des entreprises.
Cela a l'air très personnels et émotionnels comme griefs. Je vais simplement répondre à la demande concrète de votre message: "algorithme de la racine carré-inverse rapide" (de quake, je suppose).
Dans la mesure où c'est un algorithme de calcul très approximatif, et que l'instruction SSE RSQRT existe désormais, il me paraît assez peu intéressant, mais il a quand même été facile de trouver un exemple d'implémentation [playground]:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
fn inv_sqrt(x: f32) -> f32 {
    let i = x.to_bits();
    let i = 0x5f3759df - (i >> 1);
    let y = f32::from_bits(i);
 
    y * (1.5 - 0.5 * x * y * y)
}
 
 
fn print_both(v: f32) {
    println!("quake: {}", inv_sqrt(v));
    println!("real:  {}", 1.0 / v.sqrt());
    println!();
}
 
fn main() {
    print_both(4.0);
    print_both(10.0);
    print_both(3.1415);
}
Ceci-dit, le code de quake n'est pas très intéressant puisque le calcul exact tient en 3 instructions machine.
2  0 
Avatar de Pyramidev
Expert éminent https://www.developpez.com
Le 14/09/2024 à 1:47
Citation Envoyé par 23JFK Voir le message
Désolé, mais dans le code d'en haut, from_bits() semble tagué unstable.
f32::from_bits est stable depuis Rust 1.20.0. C'est le fait que cette fonction soit const (l'équivalent de constexpr en C++) qui n'est pas encore stable.
2  0 
Avatar de Pyramidev
Expert éminent https://www.developpez.com
Le 09/09/2024 à 23:30
Citation Envoyé par Stéphane le calme Voir le message
« Vous n'allez pas nous forcer à apprendre Rust », a déclaré un contributeur du noyau Linux lors d'une discussion animée au début de l'année à l'occasion d'une conférence.


Rendez-vous à 28:40
Non seulement il ne veut pas apprendre Rust, mais il est aussi contre le fait d'encoder les règles d'usage d'une API directement dans le système de types. Dans le cas où les règles changent, il dit, à 27m23 : "If that breaks Rust, we will find out whether or not this concept of encoding huge amounts of semantics into the type system is a good thing or a bad thing and instead of trying to convince us what is actually correct, let's see what happens in a year or two" (à 27m23).

Le 21 juin, Jake Edge a bien résumé cette vidéo dans son article Rust for filesystems.

Le 31 août, sur Mastodon, Asahi Lina a bien expliqué l'intérêt d'encoder les règles d'usage d'une API dans le système de types :

Citation Envoyé par Asahi Lina
I think people really don't appreciate just how incomplete Linux kernel API docs are, and how Rust solves part of the problem.

I wrote a pile of Rust abstractions for various subsystems. For practically every single one, I had to read the C source code to understand how to use its API.

Simply reading the function signature and associated doc comment (if any) or explicit docs (if you're lucky and they exist) almost never fully tells you how to safely use the API. Do you need to hold a lock? Does a ref counted arg transfer the ref or does it take its own ref?

When a callback is called are any locks held or do you need to acquire your own? What about free callbacks, are they special? What's the intended locking order? Are there special cases where some operations might take locks in some cases but not others?

Is a NULL argument allowed and valid usage, or not? What happens to reference counts in the error case? Is a returned ref counted pointer already incremented, or is it an implied borrow from a reference owned by a passed argument?

Is the return value always a valid pointer? Can it be NULL? Or maybe it's an ERR_PTR? Maybe both? What about pointers returned via indirect arguments, are those cleared to NULL on error or left alone? Is it valid to pass a NULL ** if you don't need that return pointer?

[…]

To be clear, I don't blame Linux developers for the incomplete docs. For better or worse, the Linux kernel is very complex and has to deal with a lot of subtlety. Most userspace APIs have much simpler rules you have to follow to use them safely. Kernels are hard!

Even experienced kernel developers get these things wrong all the time. It's not a skill issue. It's simply not possible for humans to keep all of these complex rules in their head and get them right, every single time. We are not built for that.

We need tooling to help us.
Mais il y a de la résistance au changement.
2  1 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 12/09/2024 à 18:00
Citation Envoyé par 23JFK Voir le message
Reste qu'apparemment, il n'est pas possible de tout faire en Rust et certain projet comme construire une librairie Rust semble carrément impossible
Je vais supposer que tu t'es mal expliqué parce qu'il est évident que Rust peut faire des bibliothèques. Le dépôt standard de Rust contient plus de 150 000 crates dont la plupart sont des bibliothèques.
Si tu voulais parler de bibliothèque qui s'interface avec d'autre langages, c'est aussi possible, à condition d'avoir une interface qui respecte l'ABI C. C'est en effet limitant, mais c'est pareil pour tout les langages qui veulent s'interfacer avec d'autres.

Citation Envoyé par 23JFK Voir le message
l'algorithme de la racine carré-inverse rapide ne semble pas non plus pouvoir être tolérée par le compilateur (spéculatif, je n'ai pas essayé ; mais étant donné qu'il faille jouer avec les différents motifs mémoire fonction du types des nombres, en Rust ça doit être un enfer) ;
C'est un peu le problème, beaucoup de gens ont un avis très tranché sur Rust, basé sur des spéculations fausses. Rust peut tout à fait faire des manipulations de bit basiques, c'est juste que les hacks comme les conversions douteuses ou les dépassement volontaires, sont remplacés par des fonctions explicites pour être sur qu'ils sont fait à dessein et que ce n'est pas des erreurs.

Citation Envoyé par 23JFK Voir le message
la compilation est affreusement lente quand il faut récupérer tous les paquets Cargo pour un gros projet.
Ça c'est vrai, mais pour le coup on ne compile pas un gros projet de zéro si souvent que ça. Quand on recompile un projet sur lequel on travaille, ça va beaucoup plus vite. Ça reste plus lent que le C mais pas vraiment plus lent que des langages plus complexes comme le C++.

Citation Envoyé par fdecode Voir le message
Ceci-dit, le code de quake n'est pas très intéressant puisque le calcul exact tient en 3 instructions machine.
Il me semble que la racine inverse rapide est encore pas mal utilisée dans la 3D, l’approximation étant relativement bonne et le gain sensible. Toutes les instructions machines ne se valent pas, 3 instructions complexes, peuvent prendre plus de cycles qu'une dizaine d'instructions plus simples.
1  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 12/09/2024 à 18:28
Après vérification, la racine inverse rapide est environ 2,5 fois plus rapide sur ma machine.
1  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 13/09/2024 à 9:48
C'est pour ça que le nombre d'instruction machine n'est pas une métrique suffisante pour mesurer la performance. Il faut aussi avoir une bonne idée de l'efficacité des instructions. Et encore le nombre de cycle d'une instruction peut varier en fonction du contexte.

Les instructions de division et de racines carrée sont connues pour être lentes. Toute l'intérêt de l’algorithme de Quake, c'est qu'il n'utilise rien de plus complexe que la multiplications.
1  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 12/09/2024 à 9:11
Citation Envoyé par NotABread Voir le message
Je ne suis pas d'accord. Je trouve que le fait que le compilateur soit plus strict ne ralenti pas le développement, car entre le moment où tu ponds ton premier binaire et le moment où tu as un binaire près pour la release, et bien tu as des phases de test même minime. Donc certes, tu mettras plus de temps à satisfaire ce tyran de compilateur, mais tu gagneras en vas-et-viens entre la plateforme de test et ton PC car toutes les erreurs de manipulation de la mémoire sont éliminé avant même que les binaires soient mis sur la plateforme.
D'autant plus qu'on finit par coder du code compilable par Rust beaucoup plus rapidement une fois acquis certains réflexes.
0  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 13/09/2024 à 9:31
Citation Envoyé par Uther Voir le message
Après vérification, la racine inverse rapide est environ 2,5 fois plus rapide sur ma machine.
Je n'ai pas fait de tests de performance pour ma part.
Le résultat de la compilation (en release) aboutit à ça:
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
.LCPI4_0:
	.long	0xbf000000
 
.LCPI4_1:
	.long	0x3fc00000
 
inv_sqrt_quake:
	movd	%xmm0, %eax
	shrl	%eax
	movl	$1597463007, %ecx
	subl	%eax, %ecx
	movd	%ecx, %xmm1
	mulss	.LCPI4_0(%rip), %xmm0
	mulss	%xmm1, %xmm0
	mulss	%xmm1, %xmm0
	addss	.LCPI4_1(%rip), %xmm0
	mulss	%xmm1, %xmm0
	retq
 
.LCPI5_0:
	.long	0x3f800000
 
inv_sqrt:
	sqrtss	%xmm0, %xmm1
	movss	.LCPI5_0(%rip), %xmm0
	divss	%xmm1, %xmm0
	retq
Donc 10 instructions pour la méthode rapide contre 3 instructions pour la méthode exacte.
Toutefois, la méthode rapide n'utilise pas de division ni d'opération racine carrée.

Ceci-dit, si je devais vraiment l'implémenter pour ma part, j'inlinerais l'instruction rsqrtss.
0  0