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 !

C-rusted : les avantages de Rust, en C sans les inconvénients,
Une analyse des trois chercheurs de l'Université de Parme en Italie

Le , par Bruno

32PARTAGES

6  0 
Le langage de programmation Rust est un projet ambitieux de la Fondation Mozilla - un langage qui prétend être la prochaine étape de l'évolution du C et du C++. Au fil des années d'existence de ces langages, certains de leurs défauts fondamentaux n'ont toujours pas été corrigés, comme les erreurs de segmentation, le contrôle manuel de la mémoire, les risques de fuites de mémoire et le comportement imprévisible du compilateur. Rust a été créé pour résoudre ces problèmes tout en améliorant la sécurité et les performances.

Roberto Bagnara, Abraham Bagnara et Federico Serafini trois chercheurs de l’Université de Parme en Italie ont produit un essai dans lequel les chercheurs présentent les avantages de Rust, en C.


Notons que Rust est un langage de programmation compilé multiparadigme, conçu par Graydon Hore alors employé chez Mozilla Research. Utilisé par plusieurs grandes entreprises et par de nombreux développeurs dans le monde, Rust est devenu le langage de base pour certaines des fonctionnalités indispensables du navigateur Firefox et de son moteur Gecko, ainsi que pour le moteur Servo de Mozilla.


Avec Rust, il est possible de développer des pilotes de périphériques, des systèmes embarqués, des systèmes d'exploitation, des jeux, des applications web, et bien d'autres choses encore. Des centaines d'entreprises dans le monde entier utilisent Rust en production pour des solutions multiplateformes et économes en ressources. Des logiciels connus et appréciés, comme Firefox, Dropbox, et Cloudflare, utilisent ce langage. De la startup à la multinationale, du système embarqué au service web à haute disponibilité, Rust serait une excellente solution.

Le langage C est un langage de programmation qui appartient au paradigme de programmation impérative. Inventé au début des 1970 dans les Laboratoires Bell pour aider la programmation du système Unix, C est devenu un des langages les plus utilisés. Il n’est pas consacré qu’à la programmation système. C’est un langage compilé, typé avec des instructions bas-niveau. Voici, ci-dessous, un exemple de programme :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
#include  
#include  
 
int somme(int); 
 
int 
main(int argc, char **arg){ 
    int i = 10; 
    printf("La somme des %d entiers est %d \n", i, somme(i)); 
return EXIT_SUCCESS ; 
}
 
int 
somme(int i){ 
    int resultat = 0; 
    for (int k = 0; k <= i; k++) 
       resultat += k; 
   return resultat; 
}

Selon les chercheurs, l’effervescence actuelle autour de Rust révèle que l'industrie est prête à accepter que les programmeurs prennent une approche plus disciplinée en adoptant un typage de données fort renforcé par des annotations de programme. C'est le véritable changement de perspective : la technologie pour assister cette nouvelle attitude dans la création de code C avec des garanties d'intégrité sans précédent est disponible, dans son essence, depuis des décennies.

DE C À C-RUSTED

Même si le langage de programmation C est (pour des raisons d'efficacité uniquement) statiquement typé, les types ne définissent que la représentation interne des données et rien de plus : les types en C n'offrent pas aux programmeurs un moyen d'exprimer les propriétés non triviales des données qui sont liées à la logique du programme. Par exemple :

  • un fichier ouvert a le même type qu'un fichier fermé ;
  • une ressource ou une transaction a le même type indépendamment de son état ;
  • une référence exclusive et une référence partagée à une ressource sont indiscernables ;
  • un nombre entier avec des valeurs spéciales qui représentent des conditions d'erreur est indiscernable d'un nombre entier ordinaire.

En C-rusted, toutes ces différences peuvent être exprimées de manière incrémentielle, ce qui permet d'améliorer la documentation, la lisibilité et la réutilisation du code. Plus important encore, cela permet à C-rusted Analyzer, qui est basé sur la plateforme de vérification logicielle, de vérifier l'exactitude avec n'importe quelle architecture, et pour chaque compilateur.

Pour illustrer, les chercheurs présentent le programme ci-dessous, que le compilateur GNU C compile sans aucun avertissement, même avec un niveau d'avertissement très élevé. Le programme contient beaucoup d'erreurs, y compris l'incrément numérique sans signification.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include 
#include 
#include 
#define BUFSIZE (100U) 
extern void process(char *string); 
int main(int argc, const char *argv[]) { 
if (argc != 2)
   return 1; 
int fd = open(argv[1], O_RDONLY); 
char *buf = (char *) malloc(BUFSIZE); 
++fd; 
ssize_t bytes = read(fd, buf, BUFSIZE - 1U); 
buf[bytes] = '\0'; 
process(buf); 
return 0;
}

Un programme C compilant sans avertissement avec gcc -c -std=c18 -Wall -Wextra -Wpedantic

Lorsqu'il est soumis à l'analyseur C-rusted, le même programme déclenche plusieurs diagnostics, résumés dans le tableau ci-dessous où la notation wn sur un point du programme signifie que l'avertissement indiqué est donné à ce point du programme.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include 
#include 
#include
 #define BUFSIZE (100U) 
extern void process(char *string); 
int main(int argc, const char *argv[]) { 
    if (argc != 2) 
        return 1; 
   int fd = open(argv[1], O_RDONLY); 
   char *buf = (char *) malloc(BUFSIZE); 
  ++fdw1; 
ssize_t bytes = read(fdw2, bufw3 , BUFSIZE - 1U); 
buf[bytes] w4w5 = '\0'; 
process(bufw6);
returnw7w8 0; 
}

w1 : Après avoir reçu la valeur de retour de open(), fd contient un descripteur de fichier ou la valeur erronée -1 : fd ne peut pas être incrémenté ;
w2, w3, w4, w5 : fd n'est pas un descripteur de fichier valide, bytes peut être -1, buf peut être NULL ;
w6 : Est-ce que process() prend la propriété, c'est à dire peut/doit-il désallouer son argument ?
w7 : Le descripteur de fichier contenu dans fd est certainement fui ici ;
w8 : La mémoire pointée par buf est possiblement divulguée ici ;

L'analyseur C-rusted donne plusieurs avertissements sur le même programme C

Une version beaucoup plus saine du programme est illustrée ci-dessous :
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
29
30
31
32
33
34
35
36
37
38
39
40
#include 
#include 
#include 
// Include C-rusted declarations, e.g., for e_hown. 
#include 
#define BUFSIZE (100U) 
// The actual parameter must be a valid (hence, non-null) pointer to a char array 
// in the heap of which process() will take ownership, which implies the caller 
// must have ownership for otherwise it would be unable to pass it on. 
extern void process(char * e_hown string); 
int main(int argc, const char *argv[]) { 
     if (argc != 2) 
          return 1; 
     int fd; // `fd` value is indeterminate. 
     fd = open(argv[1], O_RDONLY); 
     // `fd` value is either the erroneous value -1 or an open file descriptor. 
     if (fd == -1) 
          return 1; 
     // `fd` value is definitely an open file descriptor. 
     char *buf = (char *) malloc(BUFSIZE); 
     // `buf` value is either null or points to a heap-allocated char array. 
     if (buf == NULL) 
          return 1; 
     // `buf` value definitely points to a heap-allocated char array. 
     ssize_t bytes = read(fd, buf, BUFSIZE - 1U); 
     // `bytes` value is either the erroneous value -1 or the number of bytes 
    // read into `buf`. if (bytes == -1) 
           return 1; 
   // `bytes` value is definitely the number of bytes read into `buf`. 
   buf[bytes] = '\0'; 
  // process() takes ownership of `buf` and will deallocate it: no memory leak. 
 process(buf); 
 // close() properly closes the file descriptor contained into `fd`: 
 // no file descriptor leak. 
 close(fd); 
// `fd` value is an ordinary integer and cannot be used as a file descriptor 
// (it can be overwritten of course). 
// ... 
return 0; 
}
Le C-rusted Analyzer ne donne aucun avertissement sur ce program

Elle montre clairement que, bien que le type (statique) de fd soit int, pendant toute sa durée de vie, la valeur de fd a des propriétés qui changent tout au long du corps de la fonction ; de même pour buf et les bytes. En d'autres termes, le système de types C est capable de suivre les propriétés dynamiques des objets.

Selon les chercheurs, C-rusted est une solution pragmatique et rentable pour élever le jeu de la programmation C à des garanties d'intégrité sans précédent, sans renoncer à ce que l'écosystème C offre aujourd'hui. « C'est-à-dire continuer à utiliser le C, exactement comme avant, en utilisant les mêmes compilateurs et les mêmes outils, le même personnel, mais en ajoutant progressivement au programme les informations requises pour démontrer la correction, en utilisant un système d'annotations qui n'est pas basé sur la logique mathématique et qui peut être enseigné aux programmeurs en une semaine de formation. »

Ce n'est que lorsque l'ajout d'annotations montre la présence d'un problème qu'une modification du code sera nécessaire afin de corriger le bug latent qui est alors visible : dans tous les autres cas, le comportement du code restera exactement le même. Cette technique n'est pas nouvelle : elle s'appelle le typage progressif et consiste à ajouter des informations qui ne sont pas nécessaires à la compréhension du code, mais qui permettent de vérifier son exactitude.

Source : Roberto Bagnara, Abraham Bagnara et Federico Serafini, chercheurs de l’Université de Parme

Et vous ?

Quel est votre avis sur le sujet ?

Voir aussi :

Rust 1.65 est disponible, elle apporte les types génériques associés stables, ils permettent d'avoir des génériques (type, lifetime, ou const) sur les types associés

La prise en charge de Rust pour le développement du noyau Linux fait l'objet d'une nouvelle série de discussions, après une proposition de RFC

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

Avatar de smarties
Expert confirmé https://www.developpez.com
Le 22/02/2023 à 8:46
Citation Envoyé par Bousk Voir le message
Je suppose que le forcing de Rust est sensé attirer les gens à s'y intéresser. Perso ça a fini par me faire tout l'inverse
Je n'ai pas l'impression que ça soit la fondation Mozilla qui mettent en avant RUST plus que nécessaire. Je ressens plus une volonté d'un certain nombre d'entreprises et ici d'université de mettre en avant ce langage au détriment des autres.

J'ai adopté RUST mais je ne vais pas forcer les autres à l'utiliser ni dénigrer le C et le C++.
Ma pensée sur le C et le C++ est qu'ils ont fait leurs preuves, on ne va pas réécrire tout le code existant, qu'ils ont des défauts qui peuvent être corrigés en RUST. Je soutiens toutefois la question à se poser d'utiliser RUST quand on initie de nouveaux projets.
13  0 
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 21/02/2023 à 20:55
Bonjour
Citation Envoyé par Bruno Voir le message
Pour illustrer, les chercheurs présentent le programme ci-dessous, que le compilateur GNU C compile sans aucun avertissement, même avec un niveau d'avertissement très élevé. Le programme contient beaucoup d'erreurs, y compris l'incrément numérique sans signification.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include 
#include 
#include 
#define BUFSIZE (100U) 
extern void process(char *string); 
int main(int argc, const char *argv[]) { 
if (argc != 2)
   return 1; 
int fd = open(argv[1], O_RDONLY); 
char *buf = (char *) malloc(BUFSIZE); 
++fd; 
ssize_t bytes = read(fd, buf, BUFSIZE - 1U); 
buf[bytes] = '\0'; 
process(buf); 
return 0;
}
"Sans erreur ou avertissement"... Testons donc cela...
Voici le résultat de la compilation telle que mentionnée (gcc -c -std=c18 -Wall -Wextra -Wpedantic) du code cité en référence (compilateur gcc 11.3.0 sur une Ubuntu 22.04 LTS)...
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
29
30
31
32
33
x.c:1:10: error: #include expects "FILENAME" or <FILENAME>
    1 | #include
      |          ^
x.c:2:10: error: #include expects "FILENAME" or <FILENAME>
    2 | #include
      |          ^
x.c:3:10: error: #include expects "FILENAME" or <FILENAME>
    3 | #include
      |          ^
x.c: In function ‘main’:
x.c:9:10: warning: implicit declaration of function ‘open’ [-Wimplicit-function-declaration]
    9 | int fd = open(argv[1], O_RDONLY);
      |          ^~~~
x.c:9:24: error: ‘O_RDONLY’ undeclared (first use in this function)
    9 | int fd = open(argv[1], O_RDONLY);
      |                        ^~~~~~~~
x.c:9:24: note: each undeclared identifier is reported only once for each function it appears in
x.c:10:22: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
   10 | char *buf = (char *) malloc(BUFSIZE);
      |                      ^~~~~~
x.c:1:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
  +++ |+#include <stdlib.h>
    1 | #include
x.c:10:22: warning: incompatible implicit declaration of built-in function ‘malloc’ [-Wbuiltin-declaration-mismatch]
   10 | char *buf = (char *) malloc(BUFSIZE);
      |                      ^~~~~~
x.c:10:22: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
x.c:12:1: error: unknown type name ‘ssize_t’
   12 | ssize_t bytes = read(fd, buf, BUFSIZE - 1U);
      | ^~~~~~~
x.c:12:17: warning: implicit declaration of function ‘read’ [-Wimplicit-function-declaration]
   12 | ssize_t bytes = read(fd, buf, BUFSIZE - 1U);
      |                 ^~~~
Donc "sans erreur ou avertissement" faut le dire vite quoi parce que de mon côté j'ai eu l'impression que le compilo m'aurait craché à la figure s'il l'avait pu...

Citation Envoyé par Bruno Voir le message
Quel est votre avis sur le sujet ?
Ben déjà donc à partir du moment où on exagère les défauts d'un trucX c'est assez facile de promouvoir le trucY. Mais aucun langage de programmation n'est parfait. Il n'existe même pas un langage meilleur que d'autres ; il n'y a que des langages en adéquation ou peu conseillés pour des buts particuliers. (Herbert Mayer).

Mon prof de piano avec qui on discute et où on parlait des artistes en général (ceux qui accompagnent les chanteurs) m'a dit justement hier que ce ne sont pas les chanteurs qui choisissent leurs musiciens mais les autres musiciens. Et tout se fait au bouche à oreille. Si un type commence à fréquenter les milieux en se disant musicien il finira par être appelé. Mais c'est sur la scène qu'il devra prouver sa valeur. S'il joue bien on ne lui dira rien mais il sera redemandé. Et s'il ne joue pas bien, on ne lui dira rien non plus mais il ne sera plus rappelé. Je pense que c'est un peu pareil avec les langages de prog. Peut-être que le Rust est un super langage (je ne le connais que très peu donc je n'ai aucune raison de le critiquer) mais ce n'est pas en disant "ouais regardez le C ceci, le C cela" qu'il percera. C'est en faisant ses propres preuves. On ne s'élève jamais en enfonçant les autres...

[edit]
Pardon pardon, il y a une erreur dans la retranscription du code qu'a fait Bruno (hier quand j'ai testé je n'étais pas allé voir le PDF).
Le code exact de l'article commence par ces 3 lignes
Code c : Sélectionner tout
1
2
3
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
Le code recopié ici ne montre pas les include complets. Et si on corrige alors effectivement le compilateur digère le tout sans broncher.

Mais cela ne change rien au reste de ce que je pense. Le C a été conçu avec une philosophie assumée du "je laisse faire le programmeur car il sait ce qu'il fait". Donc si le programmeur fait n'importe quoi tout en restant syntaxiquement correct il n'y a aucune raison que le compilateur râle. Ce n'est donc pas la peine de venir ensuite le montrer du doigt en disant "oh regardez le compilateur n'a rien dit" car je le répète, cela était le prédicat initial et assumé de ce langage qui a, rappelons le, été créé en 1968 à l'époque où les ordinateurs n'avaient que 4Ko de RAM et qui donc peut difficilement rivaliser avec un langage du XXI° siècle. Sauf qu'en réalité il n'en a pas besoin, lui il a fait ses preuves.
10  1 
Avatar de thamn
Membre averti https://www.developpez.com
Le 21/02/2023 à 23:40
La version "beaucoup plus saine" du programme ne libere pas la memoire qu'il alloue? Dans tout le PDF, il n'y a pas un seul exemple qui ne fuite pas de memoire, et le pire c'est que l'allocation ne sert a rien, elle aurait pu etre statique.

Je sais pas peut-etre c'est une erreur, mais un "analyseur" supposé rendre le code C plus robuste qui rate ça je m'en passe volontier. Et c'est fatiguant d'entendre tout le monde essayer de rendre les autres langages similaire a Rust ou clamer que c'est possible.
9  1 
Avatar de Bousk
Rédacteur/Modérateur https://www.developpez.com
Le 21/02/2023 à 21:33
Je suppose que le forcing de Rust est sensé attirer les gens à s'y intéresser. Perso ça a fini par me faire tout l'inverse
Rust peut tout faire, et est utilisé par des centaines d'entreprises. Woohoo ce nombre est énorme. Je pense qu'il va falloir forcer encore un peu pour percer ?
10  3 
Avatar de mintho carmo
Membre éclairé https://www.developpez.com
Le 22/02/2023 à 16:51
Citation Envoyé par thamn Voir le message
le pire c'est que l'allocation ne sert a rien, elle aurait pu etre statique.
A partir du moment ou process prend un pointeur et prend l'ownership, pas d'autre choix que de faire une allocation dynamique.

Par contre, on peut critiquer le choix de design de celui qui a fait process comme ca et oblige a faire de l'allocation dynamique.

Citation Envoyé par foetus Voir le message
le commentaire dit que c'est la fonction process qui devient propriétaire et libère le buffer : "process() takes ownership of `buf` and will deallocate it: no memory leak."
Il y a un return entre le malloc et l'appel de process, donc bien une "fuite".

Citation Envoyé par foetus Voir le message
c'est du "C défensif"
Au final, pas reellement "defensif". Juste "correct".

Citation Envoyé par Sve@r Voir le message
tu as écrit une coquille en continuant le travail dans la partie if (bytes == -1).
et
Citation Envoyé par Sve@r Voir le message
Le C a été conçu avec une philosophie assumée du "je laisse faire le programmeur car il sait ce qu'il fait".
40 lignes de code et une erreur critique (ou pas, elle sera vite detectee au moindre test). Alors que foetus est un dev experiemente. Ca illustre assez bien la limite de "le dev sait ce qu'il fait".
6  0 
Avatar de foetus
Expert éminent sénior https://www.developpez.com
Le 22/02/2023 à 5:45
Citation Envoyé par thamn Voir le message
La version "beaucoup plus saine" du programme ne libere pas la memoire qu'il alloue? Dans tout le PDF, il n'y a pas un seul exemple qui ne fuite pas de memoire,
le commentaire dit que c'est la fonction process qui devient propriétaire et libère le buffer : "process() takes ownership of `buf` and will deallocate it: no memory leak."

Citation Envoyé par thamn Voir le message
et le pire c'est que l'allocation ne sert a rien, elle aurait pu etre statique.
je dirais que le pire c'est de faire l'allocation avant l'ouverture. Il y a + de chances que l'ouverture échoue que l'allocation.

Les exemples, pour moi, sont pertinents dans 1 sens : 1 développeur qui connait le C mais ne connait pas/ peu le C "industriel" (les normes, les règles de codage, le C défensif, …), tu le mets derrière cet analyseur C-rusted et son code devient presque opérationnel.
Le code "sain" ici c'est du "C défensif" du style :
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdlib.h>
 
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
 
 
#define BUFSIZE (100U)
extern void process(char* string);
 
 
int main(int argc, const char *argv[])
{
    int ret;
 
    if (argc == 2) {
        int fd = open(argv[1], O_RDONLY);
 
        if (fd != -1) {
            char* buf = malloc(BUFSIZE);
 
            if (buf != NULL) {
                ssize_t bytes = read(fd, buf, BUFSIZE - 1U);
 
                if (bytes != -1) {
                    buf[bytes] = '\0';
                    process(buf); // without free
 
                    ret = EXIT_SUCCESS;
                } else {
                    ret = 1; // error - read
                }
 
                free(buf);
            } else {
                ret = 1; // error - allocation
            }
 
            close(fd);
        } else{
            ret = 1; // error - open
        }
    } else {
        ret = 1; // error - arg
    }
 
 
    return ret;
}
Édit : @Sve@r a trouvé 1 coquille : (que j'ai corrigé)
4  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 23/02/2023 à 11:51
Citation Envoyé par Bruno Voir le message
Quel est votre avis sur le sujet ?
Que le titre "C-rusted : les avantages de Rust, en C sans les inconvénients" est très trompeur. Ce qui est proposé est très loin d'apporter au C tous les avantages du Rust. Il se contente d'apporter une version limitée du "borrow checker"

Citation Envoyé par Sve@r Voir le message
Le C a été conçu avec une philosophie assumée du "je laisse faire le programmeur car il sait ce qu'il fait". Donc si le programmeur fait n'importe quoi tout en restant syntaxiquement correct il n'y a aucune raison que le compilateur râle. Ce n'est donc pas la peine de venir ensuite le montrer du doigt en disant "oh regardez le compilateur n'a rien dit" car je le répète, cela était le prédicat initial et assumé de ce langage qui a, rappelons le, été créé en 1968 à l'époque où les ordinateurs n'avaient que 4Ko de RAM et qui donc peut difficilement rivaliser avec un langage du XXI° siècle. Sauf qu'en réalité il n'en a pas besoin, lui il a fait ses preuves.
Le truc justement, c'est que cette philosophie qui se justifiait plutôt bien dans les années 70, ne correspond plus vraiment aux standards que l'on attend de nos outils modernes. De nos jours, il n'y a pas de mal à vouloir des outils qui puissent répondre à des problématiques de sécurité, d'autant plus maintenant qu'avec des langages comme Rust, ça n'implique plus de devoir renoncer à avoir un contrôle de ce qui se passe à plus bas niveau.

Citation Envoyé par thamn Voir le message
La version "beaucoup plus saine" du programme ne libere pas la memoire qu'il alloue? Dans tout le PDF, il n'y a pas un seul exemple qui ne fuite pas de memoire, et le pire c'est que l'allocation ne sert a rien, elle aurait pu etre statique.

Je sais pas peut-etre c'est une erreur, mais un "analyseur" supposé rendre le code C plus robuste qui rate ça je m'en passe volontier. Et c'est fatiguant d'entendre tout le monde essayer de rendre les autres langages similaire a Rust ou clamer que c'est possible.
C'est sans doute la rédaction très confuse de l'article qui t'induit en erreur. Je te conseille vivement de lire directement l'article source qui est beaucoup plus clair.
Si les premiers exemples te semblent problématiques, c'est normal. Il ne s'agit pas d'exemples de code propre mais, au contraire, de code problématique pour lesquels c-rusted va pouvoir lever des warning qu'un compilateur traditionnel ne lèverait pas.
Dans la dernière version, il n'y a en effet pas de libération de mémoire, mais cette fois c'est normal : C-rusted introduit l'annotation e_hown pour indiquer que la responsabilité de gérer la mémoire est transférée à une autre fonction. Tu peux voir qu'elle est utilisée sur le paramètre de la fonction process et donc que c'est elle qui devra se charger de la libérer la mémoire. Si le code de la fonction main la libérait aussi, ça devrait au contraire lever une alerte car ça serait une erreur de double libération.

Citation Envoyé par smarties Voir le message
Je n'ai pas l'impression que ça soit la fondation Mozilla qui mettent en avant RUST plus que nécessaire. Je ressens plus une volonté d'un certain nombre d'entreprises et ici d'université de mettre en avant ce langage au détriment des autres.
En effet Rust n'a jamais eu de grand sponsors avec de gros intérêt financiers pour les pousser comme ça a pu être le cas de Sun pour Java ou Microsoft pour C#, ... et la fondation Mozilla ne met pas Rust en avant pour la simple et bonne raison quelle ne participe quasiment plus au développement du langage depuis des années. Il y a ajuste des personnes très variées qui y voient un intérêt notamment pour sécuriser les développements bas niveau.
4  0 
Avatar de mintho carmo
Membre éclairé https://www.developpez.com
Le 22/02/2023 à 17:37
Citation Envoyé par Sve@r Voir le message
Rien n'oblige au malloc (enfin je crois)
Si la fonction prend l'ownership, c'est qu'elle va appeler elle meme "free" sur le pointeur. Si c'est pas une allocation dynamique, il y a un probleme.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
void process(char *string) {
    ...
    free string; // a priori, la fonction appelle free
    ...
}
 
char s[BUFFER_SIZE]; 
process(&s); // oups
C'est d'ailleurs une des critiques du C (et en partie du C++) : le fait que l'ownership n'est pas explicite et donc que le compilateur ne peut apporter aucune garantie sur l'ownership. C'est un des points que Rust essaie de corriger, en rendant l'ownership explicite et obligatoire.
2  0 
Avatar de Freem
Membre émérite https://www.developpez.com
Le 27/11/2024 à 7:29
Citation Envoyé par foetus Voir le message
Je me rappelle de la sortie de C++11, avec lequel on nous montrait des exemples C++ moderne embarqué meilleurs que le C : exécutable, code source, …
Mais les versions sortent C++14, C++17, … mais il me semble que le C++ embarqué on n'en parle plus beaucoup
Soit on cause, soit on fait des réunions, soit on code, faut choisir.

J'ai déjà fait du baremetal en C++. Comme pour le C, tant qu'on fait du baremetal, on peut s'asseoir sur les fonctions standard qui reposent sur un OS, c'est à dire malloc et free (ou plutôt, en utiliser des versions spécialisées).
C++ a toujours permis a ma connaissance de désactiver les exceptions et la RTTI pour ce type de cadre, justement. Ca permets des binaires moins gros, évidemment utile en embarqué baremetal.
Evidemment, on ne peux plus utiliser les conteneurs standards, du coup, vu qu'ils imposent l'usage des exceptions (stupidement, selon moi, mais bon, c'était la mode dans les 90s et 00s, le tout-objet... étrangement on en reviens) mais il existe pas mal d'alternatives... Je ne serais pas surpris par exemple que EASTL soit plus adaptée au cas de l'embarqué baremetal que la STL, elle permet à priori (jamais utilisé moi-même) un contrôle plus facile de la mémoire, justement. Au pire, le conteneur le plus utile, std::vector, est trivial a réimplémenter sans exceptions, je fait ça moi-même ne serait-ce que pour pouvoir debug plus confortablement: débugguer un truc lié à la STL est pénible, a cause de tous les niveaux d'indirection et des optimisations des compilateurs qui ne sont pas désactivées par défaut même en debug... je me demande bien qui est le génie qui a eu cette idée, tiens...

Oh, et pour utiliser la RAII sans être contraint aux exceptions, c'est facile (bien qu'un peu verbeux, certes), il suffit de sortir des clous qu'on vous impose à l'école:

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
29
30
 
class foobar_t
{
 int* m_ptr = nullptr; //pour l'exemple
public:
  foobar_t( void ) = default;
 
  foobar_t( foobar_t const& ) noexcept = delete;
  foobar_t& operator=( foobar_t const& ) noexcept = delete;
 
  foobar_t( foobar_t && ) noexcept = default;
  foobar_t& operator=( foobar_t && ) noexcept = default;
 
  static init( int val )
  {
    foobar_t ret;
    ret.m_ptr = new (std::no_throw) int( val );
    return ret;
  }
 
  ~foobar_t( void )
  {
    delete m_ptr;
  }
 
  bool valid( void ) const
  {
    return m_ptr != nullptr;
  }
};
Ce bout de code simple et naïf permets d'instancier foobar_t sans jamais lancer d'exception, tout en garantissant que la destruction sera effectuée correctement (j'ai utilisé la mémoire ici parce que c'est emblématique, mais ça marche sur d'autres trucs, bien entendu).
Bon, j'ai pas testé, j'ai pondu ça en rache mode a 7H du mat en ayant mal dormi, c'est probablement pas parfait, mais l'idée est la: utiliser l'idiome des named constructors. J'avoue que j'aimerai pouvoir réduire le sucre syntaxique de tous ces constructeurs, mais bon, d'un autre côté, ça prend 30s a écrire et on est pépère après. Je sais qu'un dev doit être faignasse, mais on va pas non plus exagérer trop... sinon autant utiliser et python et s'étonner quand une merde tombe.
2  0 
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 22/02/2023 à 17:35
Citation Envoyé par mintho carmo Voir le message
Par contre, on peut critiquer le choix de design de celui qui a fait process comme ca et oblige a faire de l'allocation dynamique.
Rien n'oblige au malloc. On passe la chaine (alloué ou statique) au process qui pourra la traiter. Je pense que le malloc (avec son free déporté) ont été mis exprès pour mieux illustrer le danger du C mal écrit.

Citation Envoyé par mintho carmo Voir le message
40 lignes de code et une erreur critique (ou pas, elle sera vite detectee au moindre test). Alors que foetus est un dev experiemente. Ca illustre assez bien la limite de "le dev sait ce qu'il fait".
Ah bien vu, je me suis autobaisé
1  0