- Cpp2Rust, clang AST tabanlı sözdizimi güdümlü bir çeviricidir ve C++ girdisini otomatik olarak tamamen güvenli Rust koduna dönüştürür
- Çeviri süreci, clang ile C++ dosyasını ayrıştırıp AST oluşturur, AST üzerinde dolaşarak Rust kodunu string olarak üretir ve ardından
rustfmt ile tek bir .rs dosyası çıktısı verir
- Varsayılan olarak başvuru sayımı modeli kullanılır; hata ayıklama ve performans karşılaştırması için
--model=unsafe ile unsafe Rust üretimi de mümkündür
- Üretilen kod
libcc2rs çalışma zamanı kütüphanesine bağlıdır ve C pointer'ları null, aritmetik ve aliasing'i modelleyen Ptr<T> tipine dönüştürülür
- Tüm program çevirisi için
compile_commands.json gerekir; CMake projeleri bunu CMAKE_EXPORT_COMPILE_COMMANDS=ON bayrağıyla üretebilir
C++'tan güvenli Rust'a otomatik dönüşüm
Çeviri hattı
- Girdi C++ dosyası önce clang ile ayrıştırılarak AST oluşturulur
- Ardından AST üzerinde dolaşılarak Rust kodu string olarak üretilir
- Gerekirse
libcc2rs çalışma zamanı kütüphanesi çağrıları eklenir
- Buna örnek olarak raw pointer semantics işlenmesi verilebilir
- Son olarak Rust kodu
rustfmt kullanılarak tek bir .rs dosyası halinde düzenlenir
Güvenli Rust ve unsafe Rust modelleri
- Varsayılan davranış, başvuru sayımı modelini kullanır ve tamamen güvenli Rust çıktısı üretir
- Bir unsafe Rust üreticisi de sunulur
- Komut satırı argümanı
--model=unsafe
- Kullanım amacı hata ayıklama ve performans karşılaştırmasıdır
libcc2rs çalışma zamanı kütüphanesi
- Üretilen kod, çeviri sürecini basitleştirmek için tasarlanmış bir çalışma zamanı kütüphanesine bağlıdır
- C pointer'ları,
libcc2rs tarafından sağlanan Ptr<T> tipine dönüştürülür
Ptr<T>, C pointer semantiğini modeller
- null
- pointer aritmetiği
- aliasing
- Rust'ın borrow checker'ı denetlenen çalışma zamanı işlemleri aracılığıyla karşılanır
Derleme ve çalıştırma akışı
- Ubuntu bağımlılık kurulumu örneği
libclang-22-dev, clang++-22, ninja-build, cmake, ruff paketlerini içerir
- Derleme
cmake -GNinja .., ninja, ninja check sırasıyla yapılır
- Tek dosya çeviri komutu şu şekildedir
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
- unsafe Rust üretmek için şu şekilde çalıştırılır
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe
En küçük örnek ve tüm program çevirisi
hello.cpp içindeki printf("hello world\n") örneği, Rust'ın println!("hello world") ifadesini içeren koda dönüştürülür
- Dönüştürülen
hello.rs şu şekilde derlenir ve çalıştırılır
rustc hello.rs -L ../libcc2rs/target/debug
./hello
- Tüm program çevirisi için
compile_commands.json gerekir
- CMake'de
compile_commands.json şu bayrakla üretilir
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
- Tüm program çeviri komutu şu şekildedir
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
<dir>, compile_commands.json dosyasının bulunduğu dizin olmalıdır
Test komutları
- Tüm testler
ninja check ile çalıştırılır
- Birim testleri
ninja check-unit ile çalıştırılır
libcc2rs birim testleri ninja check-libcc2rs ile çalıştırılır
libcc2rs-macros birim testleri ninja check-libcc2rs-macros ile çalıştırılır
- Kasıtlı değişikliklerden sonra beklenen çıktıyı yeniden üretmek için
REPLACE_EXPECTED=1 ninja check-unit kullanılır
1 yorum
Lobste.rs görüşleri
Bu yıl şubatta Dan Wallach'ın sunumunu dinledim; DARPA'nın TRACTOR (Translating All C to Rust) projesini tanıtıyordu [1] [2] [3]
Araştırma programının test ve değerlendirmesinin MIT Lincoln Laboratory ekibi tarafından yürütüldüğü söyleniyor
Bildiğim kadarıyla hâlâ araştırma aşamasında, ama bu konuyla çok ilgiliyim ve böyle araçlar ile fikirlerin nasıl şekilleneceğini epey merak ediyorum
Bellek yönetiminden kaynaklanan birçok “küçük” hatayı gerçekten ortadan kaldırabilecek gibi görünüyor
[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/…
İlginç. Yazarların bununla dönüştürdüğü ve kendilerinin de ilginç bulduğu bir ya da iki kütüphane veya uygulama demosu görebilsek gerçekten harika olurdu
Örneğin https://github.com/Cpp2Rust/cpp2rust-testsuite/… bağlantısına bakınca bunun güvenli Rust olabileceğini, ama deyimsel Rust demenin kesinlikle zor olduğunu görüyorsunuz
Neden bir dönüştürme adımı gerektiğini pek anlamıyorum. Eğer bellek güvenli Rust'a dönüştürmeye yetecek kadar bilgi varsa, C++ için de statik analizle güvenli olduğunu garanti etmeye yetecek kadar bilgi yok mu?
Yaygın olarak dağıtılan yazılımlardaki güvenlik açıklarının yaklaşık %70'inin C ve C++ gibi dillerdeki bellek güvenliği hatalarından kaynaklandığı, statik analiz, sanitizer'lar ve donanımsal izolasyon gibi önlemlere onlarca yıl yatırım yapılmasına rağmen saldırganların hâlâ güvensiz bellek işlemlerini istismar ettiği söyleniyor
Uzun vadede umut vadeden çözümün mevcut C++ kod tabanlarını Rust gibi bellek güvenli dillere taşımak olduğu, ancak bunu elle yapmanın aşırı maliyetli ve hataya açık olduğu anlatılıyor
Cpp2Rust, C++ programlarını işlevsel olarak eşdeğer ve bellek güvenli Rust koduna otomatik olarak dönüştürebilen ilk sistem olduğunu iddia ediyor
Bir miktar performansı güvenlikle takas ederek, C++'ın sınırsız aliasing referansları ile Rust'ın sahiplik modeli arasındaki temel uyumsuzluğu çalışma zamanı sahiplik ve değiştirilebilirlik kontrolleri ekleyerek çözdüğünü, böylece anlamı korurken güvenliği garanti ettiğini söylüyor
Dinamik kontrol ek yükünü azaltmak için Rust kodu için kaynaklar arası optimizasyonlar da geliştirmişler; bunlar gereksiz sahiplik işlemlerini kaldırarak kaybedilen performansın önemli bir kısmını geri kazandırıyor
Yani motivasyon yalnızca güvenliği kanıtlamak değil, Rust'a taşımayı ve bundan sonraki geliştirmeleri Rust ile sürdürmeyi kolaylaştırmak
Bu tür projelerin fikri, daha sonra daha deyimsel Rust'a doğru yeniden düzenlenebilecek bir başlangıç noktası üretmek; bu da kodu analiz edilebilir hâle getirebilir
Umulur ki dönüştürülmüş koddan çalışma zamanı kontrolleri ve güvensiz kısımlar da kaldırılabilir
“C++'ı Rust benzeri” bir yapıya yeniden düzenleyip aynı şekilde analiz edilebilir kılmak mümkün değil mi denebilir, ama C++ daha fazla esneklik tanıyan farklı anlambilime sahip olduğu için analiz edilmesi gereken yollar üstel olarak artabilir ya da statik analizin belirsiz çıkmazlara girmesine yol açabilir
Statik analiz aracına zor işler çıkarmayacağınıza ve sınır durumlarını istismar etmeyeceğinize söz vermeniz gerekir; bunu yapmak için de daha kısıtlı anlambilime ve ek anotasyonlara sahip bir C++ lehçesi oluşturabilirsiniz
Circle/Safe C++ bunun mümkün olabileceğini gösterdi, ancak C++ WG bu yönelimi sert biçimde reddetti; dolayısıyla ya desteklenmeyen Rust benzeri bir C++ lehçesini kendiniz kullanacaksınız ya da doğrudan Rust kullanacaksınız
Girdi kodunun kendisi güvensizse bu tam olarak nasıl çalışıyor?