- Cpp2Rust ist ein syntaxgesteuerter Übersetzer auf Basis des clang-AST, der C++-Eingaben automatisch in vollständig sicheren Rust-Code umwandelt
- Beim Übersetzen wird eine C++-Datei mit clang geparst, daraus ein AST erstellt, der AST durchlaufen und Rust-Code als String erzeugt; anschließend gibt
rustfmt eine einzelne .rs-Datei aus
- Standardmäßig wird ein Reference-Counting-Modell verwendet; für Debugging und Performance-Vergleiche kann mit
--model=unsafe auch unsafe Rust erzeugt werden
- Der generierte Code hängt von der Runtime-Bibliothek
libcc2rs ab; C-Pointer werden in Ptr<T> umgewandelt, das null, Arithmetik und Aliasing modelliert
- Für die Übersetzung ganzer Programme ist
compile_commands.json erforderlich; bei CMake-Projekten kann sie mit dem Flag CMAKE_EXPORT_COMPILE_COMMANDS=ON erzeugt werden
Automatische Umwandlung von C++ in sicheres Rust
- Cpp2Rust ist ein Tool, das C++ automatisch in vollständig sicheres Rust übersetzt
- Es ist ein syntaxgesteuerter Übersetzer auf Basis des AST von clang
- Der Übersetzungsalgorithmus wird im auf der PLDI 2026 veröffentlichten Paper Cpp2Rust: Automatic Translation of C++ to Safe Rust beschrieben
Übersetzungs-Pipeline
- Die eingegebene C++-Datei wird zunächst mit clang geparst, um einen AST zu erzeugen
- Anschließend wird der AST durchlaufen und Rust-Code als String ausgegeben
- Bei Bedarf werden Aufrufe der Runtime-Bibliothek
libcc2rs eingefügt
- Ein Beispiel ist die Behandlung von raw pointer semantics
- Abschließend wird der Rust-Code mit
rustfmt in eine einzelne .rs-Datei formatiert
Sicheres Rust und unsafe-Rust-Modell
- Das Standardverhalten verwendet ein Reference-Counting-Modell und erzeugt vollständig sichere Rust-Ausgaben
- Ein Generator für unsafe Rust wird ebenfalls bereitgestellt
- Das Kommandozeilenargument lautet
--model=unsafe
- Zweck sind Debugging und Performance-Vergleiche
Runtime-Bibliothek libcc2rs
- Der generierte Code hängt von einer Runtime-Bibliothek ab, die entwickelt wurde, um den Übersetzungsprozess zu vereinfachen
- C-Pointer werden in den von
libcc2rs bereitgestellten Typ Ptr<T> umgewandelt
Ptr<T> modelliert die Semantik von C-Pointern
- null
- Pointer-Arithmetik
- Aliasing
- Der Borrow Checker von Rust wird durch geprüfte Runtime-Operationen zufriedengestellt
Build- und Ausführungsablauf
- Ein Beispiel für Ubuntu-Abhängigkeiten umfasst
libclang-22-dev, clang++-22, ninja-build, cmake und ruff
- Der Build erfolgt in der Reihenfolge
cmake -GNinja .., ninja, ninja check
- Der Befehl zur Übersetzung einer einzelnen Datei hat folgende Form
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
- Um unsafe Rust zu erzeugen, wird es wie folgt ausgeführt
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe
Minimalbeispiel und Übersetzung ganzer Programme
- Das Beispiel
printf("hello world\n") in hello.cpp wird in Code umgewandelt, der Rusts println!("hello world") enthält
- Die umgewandelte Datei
hello.rs wird wie folgt kompiliert und ausgeführt
rustc hello.rs -L ../libcc2rs/target/debug
./hello
- Für die Übersetzung ganzer Programme ist
compile_commands.json erforderlich
- In CMake wird
compile_commands.json mit folgendem Flag erzeugt
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
- Der Befehl zur Übersetzung eines ganzen Programms hat folgende Form
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
<dir> muss das Verzeichnis sein, das compile_commands.json enthält
Testbefehle
- Die gesamte Testsuite wird mit
ninja check ausgeführt
- Unit-Tests werden mit
ninja check-unit ausgeführt
- Unit-Tests für
libcc2rs werden mit ninja check-libcc2rs ausgeführt
- Unit-Tests für
libcc2rs-macros werden mit ninja check-libcc2rs-macros ausgeführt
- Um nach beabsichtigten Änderungen die erwartete Ausgabe neu zu generieren, wird
REPLACE_EXPECTED=1 ninja check-unit verwendet
1 Kommentare
Kommentare auf Lobste.rs
Ich habe im Februar dieses Jahres einen Vortrag von Dan Wallach gehört, in dem er das DARPA-Projekt TRACTOR (Translating All C to Rust) vorgestellt hat [1] [2] [3]
Die Tests und die Evaluation des Forschungsprogramms werden offenbar von einem Team des MIT Lincoln Laboratory durchgeführt
Soweit ich weiß, ist es noch in der Forschungsphase, aber ich interessiere mich sehr für dieses Thema und bin ziemlich gespannt, welche Tools und Ideen daraus entstehen werden
Es scheint tatsächlich viele „kleine“ Bugs beseitigen zu können, die aus der Speicherverwaltung entstehen
[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/…
Interessant. Es wäre wirklich schön, ein oder zwei Bibliotheks- oder App-Demos zu sehen, die die Autoren damit konvertiert haben und die sie selbst für interessant halten
Wenn man sich zum Beispiel https://github.com/Cpp2Rust/cpp2rust-testsuite/… ansieht, mag das sicheres Rust sein, aber idiomatisches Rust ist es ganz sicher nur schwerlich
Mir ist nicht ganz klar, warum der Konvertierungsschritt nötig ist. Wenn genug Informationen vorhanden sind, um in speichersicheres Rust zu konvertieren, hat man dann nicht auch genug Informationen, um per statischer Analyse zu garantieren, dass das C++ sicher ist?
Etwa 70 % der Sicherheitslücken in weit verbreiteter Software entstehen demnach durch Memory-Safety-Bugs in Sprachen wie C und C++; trotz jahrzehntelanger Investitionen in Gegenmaßnahmen wie statische Analyse, Sanitizer und Hardware-Isolation nutzen Angreifer weiterhin unsichere Speicheroperationen aus
Als langfristig vielversprechende Lösung wird beschrieben, bestehende C++-Codebases in speichersichere Sprachen wie Rust zu migrieren, was manuell jedoch übermäßig teuer und fehleranfällig sei
Cpp2Rust behauptet, das erste System zu sein, das C++-Programme automatisch in funktional äquivalenten und speichersicheren Rust-Code übersetzen kann
Dabei wird ein Teil der Performance gegen Sicherheit eingetauscht: Die grundlegende Diskrepanz zwischen den uneingeschränkten Alias-Referenzen von C++ und Rusts Ownership-Modell wird durch eingefügte Laufzeitprüfungen für Ownership und Mutability gelöst, wodurch die Semantik erhalten und zugleich Sicherheit garantiert werden soll
Um den Overhead der dynamischen Prüfungen zu senken, wurden außerdem Source-to-Source-Optimierungen für Rust-Code entwickelt, die redundante Ownership-Operationen entfernen und einen beträchtlichen Teil der verlorenen Performance zurückholen sollen
Die Motivation ist also nicht einfach, Sicherheit zu beweisen, sondern eher, nach Rust zu portieren und die weitere Entwicklung in Rust zu erleichtern
Die Idee solcher Projekte ist, einen Ausgangspunkt für weiteres Refactoring in idiomatischeres Rust zu schaffen; dadurch kann der Code analysierbar werden
Hoffentlich lassen sich dann im konvertierten Code auch Laufzeitprüfungen oder unsichere Teile entfernen
Man könnte sagen, man könne C++ doch genauso in eine „Rust-Form“ refaktorisieren und damit analysierbar machen; C++ hat aber andere Semantiken, die mehr Flexibilität erlauben, wodurch die zu analysierenden Pfade exponentiell zunehmen können oder die statische Analyse in unklaren Sackgassen landet
Man müsste versprechen, nichts zu tun, was statische Analysewerkzeuge vor schwierige Aufgaben stellt, und keine Grenzfälle auszunutzen; dafür könnte man einen C++-Dialekt mit eingeschränkterer Semantik und zusätzlichen Annotationen schaffen
Circle/Safe C++ hat gezeigt, dass das möglich ist, aber die C++ WG hat diese Richtung deutlich abgelehnt; damit bleibt nur, selbst einen nicht unterstützten, Rust-ähnlichen C++-Dialekt zu verwenden oder einfach Rust zu nutzen
Was genau passiert, wenn der Eingabecode selbst unsicher ist?