1 points par GN⁺ 3 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Cpp2Rust est un traducteur syntaxique piloté par l’AST de clang, qui convertit automatiquement du code C++ en code Rust entièrement sûr
  • Le processus de traduction consiste à analyser les fichiers C++ avec clang pour produire un AST, à parcourir cet AST pour générer du code Rust sous forme de chaînes, puis à produire un unique fichier .rs avec rustfmt
  • Le modèle par défaut est le modèle à comptage de références ; pour le débogage et les comparaisons de performances, il est aussi possible de générer du Rust unsafe avec --model=unsafe
  • Le code généré dépend de la bibliothèque d’exécution libcc2rs, et les pointeurs C sont convertis en Ptr<T>, qui modélise les valeurs nulles, l’arithmétique des pointeurs et l’aliasing
  • La traduction d’un programme complet nécessite compile_commands.json ; pour les projets CMake, il peut être généré avec l’option CMAKE_EXPORT_COMPILE_COMMANDS=ON

Conversion automatique de C++ vers un Rust sûr

  • Cpp2Rust est un outil qui traduit automatiquement du C++ vers un Rust entièrement sûr
  • Il s’agit d’un traducteur syntaxique basé sur l’AST de clang
  • L’algorithme de traduction est décrit dans l’article publié à la PLDI 2026 : Cpp2Rust: Automatic Translation of C++ to Safe Rust

Pipeline de traduction

  • Le fichier C++ d’entrée est d’abord analysé avec clang pour générer un AST
  • Cet AST est ensuite parcouru pour produire le code Rust sous forme de chaînes
  • Si nécessaire, des appels à la bibliothèque d’exécution libcc2rs sont insérés
    • Un exemple est le traitement de la sémantique des pointeurs bruts
  • Enfin, rustfmt est utilisé pour formater le code Rust dans un unique fichier .rs

Modèles Rust sûr et Rust unsafe

  • Le comportement par défaut utilise le modèle à comptage de références et produit une sortie Rust entièrement sûre
  • Un générateur de Rust unsafe est également fourni
    • L’argument en ligne de commande est --model=unsafe
    • Il sert au débogage et aux comparaisons de performances

Bibliothèque d’exécution libcc2rs

  • Le code généré dépend d’une bibliothèque d’exécution conçue pour simplifier le processus de traduction
  • Les pointeurs C sont convertis vers le type Ptr<T> fourni par libcc2rs
  • Ptr<T> modélise la sémantique des pointeurs C
    • null
    • arithmétique des pointeurs
    • aliasing
  • Le borrow checker de Rust est satisfait via des opérations d’exécution vérifiées

Processus de build et d’exécution

  • L’exemple d’installation des dépendances sur Ubuntu inclut libclang-22-dev, clang++-22, ninja-build, cmake, ruff
  • Le build s’effectue dans l’ordre cmake -GNinja .., ninja, ninja check
  • La commande de traduction d’un fichier unique prend la forme suivante
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
  • Pour générer du Rust unsafe, exécutez la commande suivante
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe

Exemple minimal et traduction d’un programme complet

  • L’exemple printf("hello world\n") de hello.cpp est converti en code Rust contenant println!("hello world")
  • Le fichier converti hello.rs se compile et s’exécute ainsi
rustc hello.rs -L ../libcc2rs/target/debug
./hello
  • La traduction d’un programme complet nécessite compile_commands.json
  • Avec CMake, compile_commands.json est généré avec l’option suivante
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
  • La commande de traduction d’un programme complet prend la forme suivante
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
  • <dir> doit être le répertoire contenant compile_commands.json

Commandes de test

  • Tous les tests s’exécutent avec ninja check
  • Les tests unitaires s’exécutent avec ninja check-unit
  • Les tests unitaires de libcc2rs s’exécutent avec ninja check-libcc2rs
  • Les tests unitaires de libcc2rs-macros s’exécutent avec ninja check-libcc2rs-macros
  • Pour régénérer les sorties attendues après une modification volontaire, utilisez REPLACE_EXPECTED=1 ninja check-unit

1 commentaires

 
GN⁺ 3 시간 전
Avis sur Lobste.rs
  • J’ai assisté en février dernier à une présentation de Dan Wallach, où il a présenté le projet TRACTOR (Translating All C to Rust) de la DARPA [1] [2] [3]
    Il a indiqué que les tests et l’évaluation du programme de recherche étaient actuellement menés par l’équipe du MIT Lincoln Laboratory
    À ma connaissance, c’est encore au stade de la recherche, mais le sujet m’intéresse beaucoup et je suis assez curieux de voir ce que ce type d’outils et d’idées peut donner
    On dirait que cela pourrait réellement éliminer beaucoup de bugs “mineurs” liés à la gestion mémoire
    [1] https://www.darpa.mil/research/programs/translating-all-c-to-rust
    [2] https://github.com/DARPA-TRACTOR-Program
    [3] https://ll.mit.edu/r-d/projects/…

  • Intéressant. J’aimerais vraiment pouvoir voir une ou deux démos de bibliothèques ou d’applications que les auteurs ont converties avec ça et qu’ils jugent eux-mêmes convaincantes

  • Je ne comprends pas bien pourquoi une étape de traduction est nécessaire. S’il y a suffisamment d’informations pour convertir vers du Rust sûr du point de vue mémoire, n’y aurait-il pas aussi assez d’informations pour garantir par analyse statique que le C++ est sûr ?

    • L’idée est d’ajouter de nouvelles vérifications pendant la conversion, donc le compromis est moins “le code d’origine était sûr” que “le nouveau code s’arrête en échouant bruyamment au lieu de corrompre la mémoire”
    • C’est expliqué au début de l’article lié dans le README
      Environ 70 % des vulnérabilités de sécurité dans les logiciels largement diffusés proviennent de bugs de sûreté mémoire dans des langages comme C et C++, et malgré des décennies d’investissement dans des mesures d’atténuation comme l’analyse statique, les sanitizers ou l’isolation matérielle, les attaquants continuent d’exploiter des opérations mémoire non sûres
      À long terme, une solution prometteuse consiste à migrer les bases de code C++ existantes vers un langage à sûreté mémoire comme Rust, mais le faire à la main coûte trop cher et reste sujet aux erreurs
      Cpp2Rust affirme être le premier système capable de traduire automatiquement des programmes C++ en code Rust fonctionnellement équivalent et sûr du point de vue mémoire
      En échangeant une partie des performances contre la sécurité, il résout l’incompatibilité fondamentale entre les références aliasées sans restriction du C++ et le modèle de possession de Rust en insérant des vérifications d’exécution de possession et de mutabilité, afin de préserver la sémantique tout en garantissant la sûreté
      Pour réduire le surcoût des vérifications dynamiques, ils ont aussi créé des optimisations interprocédurales pour le code Rust, qui éliminent les opérations de possession redondantes et récupèrent une bonne partie des performances perdues
      Donc l’objectif n’est pas simplement de prouver la sûreté, mais plutôt de porter vers Rust et de faciliter la poursuite du développement en Rust
    • Il n’y a pas assez d’informations, et selon le théorème de Rice, il n’y en aura jamais
      L’idée de ce genre de projet est de produire un point de départ pour refactorer davantage vers un Rust idiomatique, ce qui peut ensuite rendre le code analysable
      Avec un peu de chance, cela permettra aussi de supprimer les vérifications d’exécution ou les parties non sûres du code traduit
      On pourrait dire qu’il suffirait de refactorer le C++ en une forme “qui ressemble à Rust” pour le rendre tout aussi analysable, mais le C++ a une sémantique différente qui autorise bien plus de flexibilité, ce qui peut faire exploser exponentiellement le nombre de chemins à analyser ou mener l’analyse statique dans des impasses ambiguës
      Il faut promettre de ne pas faire des choses difficiles pour les analyseurs statiques ni d’exploiter les cas limites, et pour cela on pourrait créer un dialecte de C++ avec une sémantique plus restreinte et des annotations supplémentaires
      Circle/Safe C++ a montré que c’était possible, mais comme le WG C++ a fortement rejeté cette direction, il ne reste plus qu’à utiliser soi-même un dialecte de C++ proche de Rust sans support officiel, ou simplement utiliser Rust
  • Comment cela fonctionne-t-il exactement lorsque le code d’entrée lui-même est non sûr ?

    • C’est géré par des vérifications d’exécution. Ainsi, au moment où une violation se produit, le programme peut planter de manière sûre et déterministe au lieu de corrompre la mémoire