2 poin oleh GN⁺ 2024-12-22 | 1 komentar | Bagikan ke WhatsApp
  • Scylla mengusulkan jalur untuk secara bertahap menstrukturkan C asli agar dapat langsung dikompilasi menjadi Rust yang aman, alih-alih memindahkan C lama ke unsafe Rust lalu memperbaikinya
  • Targetnya adalah subset C aplikatif yang mencakup pemrosesan data, operasi pointer, alur kontrol terstruktur, dan kode portabel; kode yang bergantung pada goto, cast integer-pointer, trik pointer, bitfield, dan untagged union dikecualikan
  • Transformasinya terdiri dari 2 tahap: menurunkan Clang AST menjadi Mini-C, lalu memindahkannya ke safe Rust; perilaku halus C seperti promosi integer, konversi implisit, ekspresi assignment, serta increment prefix/postfix dibuat eksplisit
  • Aritmetika pointer yang paling sulit diubah menjadi pemecahan berbasis Rust slice dan split_at_mut/split_at, sekaligus menangani inferensi mutabilitas, derivasi trait, serta pemilihan Box dan borrow
  • Mereka mengevaluasi SymCrypt Windows, HACL★, algoritme kompresi inti bzip2, parser/serializer CBOR EverParse, serta sebagian Microsoft FrodoKEM; selama transformasi juga ditemukan undefined behavior pada bzip2 dan FrodoKEM

Jalur transisi C→Rust yang dipilih Scylla

  • Motivasi untuk memindahkan kode C lama ke Rust berawal dari masalah keamanan memori
    • Riset Google dan Microsoft memperkirakan 70% kerentanan keamanan berkaitan dengan penanganan memori yang keliru
    • Perusahaan dan pemerintah mendorong penggunaan bahasa yang aman memori seperti Rust untuk sistem yang kritis terhadap keselamatan
  • Rust memiliki keunggulan jelas untuk kode baru, tetapi sulit menulis ulang seluruh kode C industri yang sudah diuji dan di-debug
  • Tool konversi otomatis C→Rust yang ada umumnya menghasilkan unsafe Rust agar dapat mendukung seluruh C
    • Mengizinkan idiom ala C seperti unchecked pointer atau transmutation di Rust
    • Jaminan keamanan memori statis hilang, sehingga tujuan memakai safe language menjadi lebih lemah
  • Workflow umum adalah menjadikan output unsafe Rust sebagai titik awal, lalu melakukan refactoring berulang menjadi Rust yang aman
    • Ada analisis statis yang diusulkan untuk mengganti raw pointer dengan borrow safe Rust, atau memulihkan abstraksi Rust dari representasi level rendah
    • Tool refactoring tersebar, dan dukungan c2rust refactor juga dihentikan pada 2022
  • Alih-alih memperbaiki unsafe Rust yang dihasilkan, Scylla memilih cara menstrukturkan kode C asli itu sendiri secara bertahap agar dapat dikompilasi menjadi safe Rust

Subset C yang didukung dan pola yang dikecualikan

  • Tujuan Scylla adalah menghasilkan transformasi yang dapat diprediksi dan kode Rust yang dekat dengan C asli
  • Target yang didukung adalah subset C aplikatif
    • Kode yang memanipulasi dan memproses data
    • Kode yang menggunakan aritmetika pointer
    • Kode dengan alur kontrol terstruktur
    • Kode portabel
  • Codebase yang bergantung pada pola berikut tidak didukung
    • goto
    • Penggunaan representasi objek melalui cast integer-pointer
    • Trik pointer
    • Bitfield
    • Untagged union
  • Developer dapat menerapkan rewrite dan anotasi terarah pada source C agar dapat dipahami Scylla
    • Pola aliasing yang tidak cocok dengan Rust borrow checker dapat ditulis ulang
    • Developer dapat memberi informasi kepada Scylla bahwa tagged union harus diterjemahkan menjadi ADT level tinggi

Mini-C: bahasa perantara yang mengurangi ambiguitas C

  • Scylla berangkat dari AST frontend Clang, lalu pertama-tama mentransformasikannya ke bahasa bernama Mini-C
  • Mini-C menangani branch, loop, pointer, dereference, dan pengambilan alamat seperti C, tetapi memiliki semantik “no-surprises”
    • Semua integer memiliki lebar tetap
    • Integer promotion dan integer conversion C direpresentasikan sebagai cast eksplisit
    • Untyped pointer seperti void * tidak diizinkan
  • Berbeda dari C, Mini-C adalah bahasa ekspresi
    • Assignment tidak mengembalikan nilai
    • Sintaks C seperti e1 = e2 = e3 dan p[i++] di-desugar di Mini-C
    • Ekspresi pengujian pada loop dan conditional harus bertipe bool, bukan int seperti di C
  • Saat memindahkan typed AST Clang ke typed AST Mini-C, perilaku implisit C dibuat eksplisit
    • Ekspresi kondisi disesuaikan menjadi bool
    • Indeks array disesuaikan menjadi size_t
    • Konversi implisit pada argumen pemanggilan fungsi dan sisi kanan assignment diubah menjadi cast eksplisit
    • Pada operasi aritmetika, usual arithmetic conversions dari standar C direfleksikan
  • Transformasi mengasumsikan kode C portabel dan tidak bergantung pada model data C
    • Misalnya, kode yang perilakunya berubah tergantung apakah long berukuran 4 byte atau 8 byte tidak diharapkan
    • Implementasi mendeteksi model data arsitektur target pada configure-time dan mengubah unsigned int menjadi tipe lebar tetap seperti uint32_t

Sintesis ADT dan tuple

  • Mini-C menyediakan ADT, tuple, dan pattern matching dengan level yang lebih tinggi daripada C
  • Tagged union diterjemahkan menjadi ADT melalui anotasi
    • Bentuk targetnya adalah struktur seperti { int tag; union { t0 case0; ...; tn caseN }}
    • Nilai tag berada dari 0 hingga N, dan diasumsikan nilai tag sesuai dengan urutan case union
  • Scylla mengubah tipe tagged union yang dianotasi menjadi tipe variant
    • Saat membuat nilai, Scylla memeriksa apakah .tag = i dan .casej = e cocok
    • Jika cocok, nilai tersebut diubah menjadi nilai constructor terkait
    • Jika payload dan tag tidak cocok, ia tidak diterjemahkan ke Mini-C
  • Akses field tagged union aman hanya jika status tag saat ini diketahui
    • Scylla mengenali pola seperti if (x.tag == i) { ... x.casei } atau switch
    • Ini diubah menjadi bentuk match x with | Ci v -> ...
    • Akses ke union case lain dianggap invalid dan menghasilkan error transformasi
  • Tuple juga dapat disintesis melalui anotasi
    • Struct dengan n field diubah menjadi tuple n-ary
    • Akses field berubah menjadi akses field tuple
    • Tuple memiliki tipe secara struktural sehingga dapat memperoleh manfaat dari mut-polymorphism

Transformasi dari Mini-C ke safe Rust

  • Mini-C menyediakan representasi program C dengan anotasi tipe lengkap, lalu ditransformasikan menjadi safe Rust
  • Ada tiga kesulitan utama
    • Menghapus aritmetika pointer C
    • Mengeksplisitkan mutabilitas dan aliasing
    • Menyediakan struktur idiomatis Rust seperti trait secara otomatis
  • Transformasi tipe pointer rumit karena perbedaan representasi pointer di Rust
    • Rust membedakan Box<T> dan &T
    • Pointer elemen tunggal dan pointer multi-elemen juga dibedakan, misalnya &T dan &[T]
    • Array Rust adalah value dan tidak otomatis decay menjadi pointer seperti di C
  • Strategi dasarnya adalah mengompilasi semua pointer type C menjadi slice borrow Rust &[T]
    • Pointer stack maupun heap secara default menjadi slice borrow
    • Pointer elemen tunggal maupun multi-elemen juga secara default menjadi slice borrow
    • Mutabilitas diinferensikan otomatis pada tahap terpisah
  • Scylla menerjemahkan sebagian pointer menjadi Box<T> melalui heuristik dan anotasi manual
    • Fungsi seperti T *create() yang dianggap fresh allocation dan tidak memiliki referensi global dapat diterjemahkan menjadi fn create() -> Box<T>
    • Analisis ini diterapkan secara rekursif dengan metode fixed point hingga ke dalam definisi struct dan variant
    • Struct yang masih memiliki borrow akan memiliki lifetime parameter

Batasan transformasi Box, slice, dan array

  • Karena Rust memerlukan konversi eksplisit antara array, slice borrow, dan Box, transformasi Rust Scylla juga bekerja secara type-directed
  • Aturan transformasi menyisipkan coercion yang mengubah array atau boxed slice menjadi slice borrow
    • Array menjadi slice borrow dalam bentuk seperti &x[..]
    • Boxed slice dapat dikonversi menjadi borrow
  • Transformasi arah sebaliknya juga memungkinkan
    • Slice atau array dapat dipromosikan menjadi heap allocation dan diubah menjadi Box<[T]>
  • Transformasi arah sebaliknya ini dapat menimbulkan perbedaan semantik penyalinan
    • Di C, array dan pointer dapat menunjuk ke memori yang sama
    • Di Rust, Box::new(x) dapat membuat copy dari x
    • Array tipe dasar seperti array integer tidak dapat opt out dari trait Copy, sehingga Rust dapat melakukan penyalinan diam-diam
  • Jika transformasi seperti ini terjadi, Scylla menghapus variabel asli dari environment agar penggunaan berikutnya dilarang
    • Jika program C asli terus menggunakan variabel tersebut, akan terjadi error transformasi
    • Developer perlu memperbaiki source C sebelum transformasi agar maksudnya lebih jelas

Mengubah aritmetika pointer menjadi pemecahan Rust slice

  • Program C sering tidak hanya mengakses array dengan satu base pointer, tetapi juga membagi array menjadi chunk atau menelusurinya sambil mempertahankan pointer posisi saat ini
  • Rust tidak mengizinkan aritmetika pointer sembarang, dan menyediakan cara membagi slice dengan split_at_mut atau split_at
    • split_at_mut adalah primitive yang melepaskan kepemilikan slice asli dan memperoleh dua sub-slice
    • Ini mempertahankan invariant Rust bahwa mutable data harus memiliki owner yang unik
  • Scylla memperkenalkan split tree untuk menyelaraskan aritmetika pointer C dengan cara pemecahan Rust
    • Setiap pointer C dipetakan ke satu split tree
    • Split tree berubah secara flow-dependent
    • Split tree melacak akses pointer C pada titik program tertentu harus diubah menjadi akses slice Rust yang mana
  • Karena pointer C tidak memiliki informasi panjang, Scylla mengasumsikan chunk tidak saling tumpang tindih
    • Jika memang dimaksudkan tumpang tindih, pemeriksaan tipe Rust tidak dapat lolos, dan developer harus menulis ulang kode C
    • Agar transformasi dapat diprediksi, proses dilakukan secara forward dan menghindari backtracking
  • Dalam contoh, array 32 byte abcd dibagi menjadi empat area limb berukuran 8 byte
    • Di C, aritmetika pointer digunakan tidak dalam urutan kiri-ke-kanan, seperti abcd + 0, abcd + 16, abcd + 8, abcd + 24
    • Transformasi Rust mempertahankan riwayat pemanggilan split_at_mut sebagai split tree untuk menemukan sub-slice yang benar

Target evaluasi dan undefined behavior yang ditemukan

  • Implementasi Scylla menggunakan Clang untuk menerima kode C lama sebagai input dan menghasilkan safe Rust
  • Target evaluasi mencakup bagian dari beberapa proyek C yang ada
    • Sebagian SymCrypt di Windows
    • Sebagian pustaka kriptografi HACL★
    • Bagian inti dari algoritme kompresi bzip2
    • Parser dan serializer binary CBOR dari pustaka EverParse
    • Implementasi primitive kriptografi post-quantum FrodoKEM dari Microsoft
  • Kasus-kasus ini menunjukkan bahwa subset C aplikatif Scylla dapat mencakup berbagai aplikasi yang sensitif terhadap keamanan
  • Dalam proses transformasi, mereka juga mengidentifikasi dan melaporkan undefined behavior yang ada pada kode C asli bzip2 dan FrodoKEM

1 komentar

 
GN⁺ 2024-12-22
Komentar Hacker News
  • Penting untuk dicatat bahwa pekerjaan ini ditujukan pada “basis kode C yang sudah diverifikasi secara formal
    Kode C sistem pada umumnya tidak diverifikasi secara formal, jadi ini adalah cerita yang cukup berbeda

    • Meski begitu, tampaknya hasilnya tetap tidak sepenuhnya bisa dipercaya. Bahkan di bagian 2.2 makalahnya disebutkan bahwa paksaan yang diperkenalkan oleh aturan transformasi dapat menciptakan perbedaan makna yang halus
      Misalnya, pointer yang tadinya menunjuk ke array C di stack bisa diterjemahkan di Rust menjadi pointer yang memiliki salinan heap baru sebagai Box<[u8]>. Jika kode aslinya bergantung pada fakta bahwa pointer tersebut benar-benar menunjuk ke array asli, kode hasil terjemahan bisa diam-diam berjalan salah
      Dalam fitur terjemahan otomatis subset C++ aman terhadap memori di proyek saya, scpptool, hal seperti ini akan ditangani dengan memindahkan array ke tipe pengganti dan iterator agar makna aslinya tetap terjaga
      Mungkin proyek OP memang hanya menangani C yang mudah diubah menjadi Rust aman, tetapi mengingat tingkat kesulitannya, hasil ini tetap patut dihargai dan tampak punya kegunaan sampai batas tertentu
    • Ini punya jauh lebih banyak catatan kehati-hatian, dan nyaris seperti iklan berlebihan
      Sejak awal mereka sebenarnya tidak menerjemahkan C nyata, melainkan mengubah sisi kompiler agar kode yang ditulis dalam F* mengeluarkan Rust. Mereka tidak berhadapan dengan C dunia nyata yang kompleks, paling-paling hanya menangani Mini-C terbatas yang mungkin dikeluarkan kompiler mainan
      Di tulisan aslinya juga disebutkan bahwa jika program C asal terlalu bergantung pada x, terjemahan akan menghasilkan error dan meminta programmer memodifikasi sumbernya; ini berarti mereka berharap C tersebut sudah ditulis dalam gaya yang memuaskan borrow checker Rust
      Ini terasa seperti ungkapan akademik untuk “Gambar 4 menyajikan aturan yang indah, tetapi implementasi nyatanya bergantung pada banyak trik”
      Lebih buruk lagi, jika ada overlap yang bisa dibedakan secara statis maka akan terjadi error kompilasi, dan jika tidak maka kode Rust bisa panic saat runtime. Mengubah program C yang diverifikasi secara formal menjadi program Rust yang “sekarang bisa crash” terasa aneh
      Menyebut HACL* sebagai basis kode C yang sudah diverifikasi secara formal juga tidak akurat. HACL* memang dikompilasi ke C, tetapi bukan pustaka C; ia ditulis dalam bahasa yang sepenuhnya berbeda
      Judul yang jujur seharusnya kira-kira: “Mengompilasi subset F* ke Rust yang sebagian aman, dengan formalisasi sebagian”
    • Apakah Rust sendiri diverifikasi secara formal? Setahu saya tidak
    • Saya penasaran apa tepatnya yang dimaksud dengan C yang diverifikasi secara formal, dan mengapa tidak lebih banyak
    • Saya penasaran apa perbedaan intinya. Apakah kepatuhan bisa dipaksakan lewat flag kompiler?
  • Pada tahun 2002, para peneliti menerbitkan makalah tentang Cyclone, dialek C yang aman, dan saat memindahkan kode C ke Cyclone secara manual mereka menemukan bug keamanan pada kode C yang sudah ada
    Transformasi C seperti ini, baik manual maupun otomatis, bukan hanya berpotensi meningkatkan adopsi bahasa yang lebih aman, tetapi juga mengungkap bug lama
    [1] https://www.researchgate.net/profile/James-Cheney-2/publicat...

    • Cyclone sudah tidak lagi didukung, proyek riset intinya juga telah berakhir, dan para pengembangnya sudah pindah ke pekerjaan lain
      Banyak ide dari Cyclone masuk ke Rust, dan kodenya masih bisa dibuat jalan dengan usaha, tetapi tidak langsung bisa dibangun di platform 64-bit modern
      http://cyclone.thelanguage.org
  • Saya pernah memakai C2Rust sebagai langkah awal untuk mem-porting beberapa proyek, termasuk proyek C, ke Rust, dan mendapat beberapa kesimpulan

    1. Saat program C dipindahkan ke Rust, bahkan jika mengandung unsafe, bug sering kali lebih cepat terungkap berkat batasan kuat Rust, seperti pemeriksaan batas dan signature yang ketat
    2. Saya rasa transformasi otomatis C→Rust tidak akan pernah bisa sepenuhnya diselesaikan. Desain program C secara mendasar berbeda dari Rust, dan untuk membuatnya aman diperlukan desain ulang yang cukup besar
    3. Dalam beberapa kasus, tidak mungkin memindahkan C ke Rust sambil mempertahankan makna yang tepat. Ketidakamanan bisa melekat pada desainnya sendiri
      Meski begitu, alat tetap penting untuk porting, dan semakin alatnya berkembang, prosesnya akan makin mulus
    • Mengubahnya secara otomatis menjadi “Rust yang cepat dan aman” itu sulit, tetapi mengubahnya secara otomatis menjadi Rust aman biasa jauh lebih mudah
      Caranya adalah merepresentasikan memori sebagai array dan memperlakukan pointer sebagai indeks ke array tersebut. Dengan begitu, perilaku C seperti aritmetika pointer tanpa pemeriksaan atau union bisa diekspresikan tanpa harus melawan borrow checker, dan maknanya tetap terjaga. Teknik serupa juga sudah lama dipakai dalam C→Java
      Tentu saja nilai dari transformasi seperti ini agak meragukan. Pada dasarnya ini mirip mengompilasi C ke wasm tetapi lebih lambat, dan walaupun kode hasilnya secara teknis “aman”, masalah seperti buffer overflow yang menciptakan state salah atau dangling pointer yang memungkinkan akses data dalam konteks yang seharusnya tidak diizinkan tetap ada
    • Saya pada prinsipnya setuju dengan pernyataan bahwa “ketidakamanan bisa melekat pada desain”, dan dari pengalaman saya juga terasa sangat benar, tetapi akan bagus jika ada contoh sederhana untuk membuat pembahasannya lebih konkret
  • Saya penulisnya. Rasanya akan membantu jika saya merangkum beberapa hal yang muncul dari beberapa thread

    1. Ini adalah makalah akademik yang diunggah ke arxiv, bukan pengumuman produk baru yang mengklaim telah menyelesaikan masalah C→Rust. Ini diajukan ke konferensi PL, dan audiens serta ekspektasinya berbeda dari presentasi di acara open source seperti FOSDEM
    2. Pendekatannya sederhana. Berangkat dari batasan menerjemahkan C ke Rust yang aman, kami melihat perlunya subset kecil C yang dapat berfungsi dengan baik, inferensi pemisahan slice, terjemahan yang bisa gagal, dan program yang bisa dihentikan. Kami mengevaluasinya pada target yang kami miliki, yaitu C yang di-embed di dalam F*, dan menunjukkan bahwa di bawah batasan ini pendekatan tersebut cukup skalabel pada library C besar yang digunakan dalam perangkat lunak arus utama seperti Firefox dan Python. Kami tidak mengklaim bisa menulis ulang Firefox ke Rust secara otomatis
    3. Memang begitulah penelitian berjalan. Kami melihat ada titik menarik dalam ruang desain, dan meskipun tidak mengklaim menyelesaikan semua masalah, kami menganggap ini sebagai ide yang dapat membuka kemajuan lebih lanjut di bidang penerjemahan C→Rust. Beberapa alat yang sudah ada mungkin dapat memakai pendekatan ini untuk kode yang sesuai dengan subset tersebut, dan melakukan fallback ke unsafe Rust untuk bagian yang tidak cocok
    4. Ini bukan versi final. Kami sedang membuat frontend C yang nyata dengan libclang, dan juga sedang mengeksplorasi cara menjamin bahwa Rust yang dihasilkan tidak membuat akses di luar batas. Misalnya, kami sedang mempertimbangkan untuk mengekspor kondisi verifikasi ke Z3. Jika reviewer menilai masih perlu lebih banyak pekerjaan, kami bisa memperbaikinya lalu mengajukan ulang; dan akan lebih baik jika makalah ini diterima karena bidang ini aktif dan orang lain mungkin bisa mengambil manfaat dari ide-idenya
  • Yang benar-benar membuat saya penasaran adalah mengapa ini harus dilakukan
    Jika ini adalah teknologi yang benar-benar bisa mengonversi aplikasi industri dari C ke Rust, tampaknya itu juga bisa mempermudah membentengi aplikasi C yang sudah ada. Cukup buat analisis yang bisa dimasukkan ke alat yang sudah ada seperti penganalisis statis atau pembangkit uji
    Demikian juga, kita bisa membuat wrapper yang aman sehingga kode baru dapat ditulis dalam Rust di samping C yang sudah diverifikasi. Kode baru mendapat manfaat Rust, kode lama dipastikan aman, dan antarmukanya juga menjadi lebih aman
    Penerjemah penuh mungkin ideal. Dalam jangka panjang, memang bagus bila codebase hanya punya satu bahasa. Tetapi untuk C/C++ yang sudah ada, kebutuhan terbesar tetaplah pengamanan sekali klik dengan sedikit false positive. Mungkin juga dimungkinkan untuk secara otomatis memperbaiki struktur buruk di dalam C, seperti alat compiler milik Google atau Mayhem dari ForAllSecure

    • Sebagian program C memang tidak bisa dibuat aman, jadi pernyataan “jika ada teknologi untuk mengubah aplikasi industri ke Rust maka aplikasi C juga bisa lebih mudah dibentengi” itu tidak tepat
      Mungkin karena program tersebut bergantung pada undefined behavior atau unspecified behavior, atau karena jika pemeriksaan keamanan yang layak ditambahkan, rentang input yang diizinkan menyusut terlalu banyak hingga menjadi tidak berguna
      Menerjemahkannya ke bahasa yang aman secara objektif lebih baik dalam kasus seperti ini karena ekspresivitas input dapat dipertahankan sambil menjamin perilaku yang benar saat dijalankan secara statis
      Gagasan tentang “C yang sudah terbukti di lapangan” juga sulit dikatakan benar-benar ada, seperti yang ditunjukkan oleh banyaknya kerentanan fatal. Yang benar-benar ada hanyalah C yang cukup sering bekerja cukup baik sehingga tampak berguna
      Kode lama diasumsikan aman karena beruntung, bukan karena terbukti. “Bukti” punya makna khusus, terutama dalam konteks makalah seperti ini, dan mayoritas besar kode C tidak terbukti menurut standar matematis yang ketat. Sebaliknya, sistem tipe Rust telah terbukti benar secara matematis
      Penerjemah penuh bergantung pada apa yang rela Anda korbankan. Jika Anda rela mengorbankan performa, rentang input, rentang output, keterbacaan kode, dan sebagainya, mungkin sampai taraf tertentu itu bisa dilakukan; tetapi begitu Anda mulai menginginkan penerjemah yang sound dan complete di semua aspek itu, masalah akan muncul
  • Kalau diterjemahkan ke Rust secara naif, bukankah hasilnya akan mencampur bagian yang aman dan bagian unsafe? Kalau begitu, tampaknya pekerjaan manual cukup memeriksa keamanan area unsafe saja. Mirip seperti saat menulis Rust dari awal
    Jika 90% hasilnya bukan unsafe, itu tampak cukup menguntungkan

    • Memang benar. Seseorang pernah mencoba mengonversi OpenJPEG dengan c2rust menjadi unsafe Rust tingkat rendah
      OpenJPEG diketahui mengalami segfault pada kasus uji tertentu, dan ketika uji itu dijalankan pada versi Rust, segfault juga terjadi pada kode Rust yang sesuai di lokasi yang sama. Setidaknya berarti tetap kompatibel
      Tetapi pendekatan itu adalah jalan buntu. Untuk benar-benar maju, penerjemah harus mengenali idiom umum C dan mengangkatnya ke bentuk yang alami dalam bahasa target. Jika “dikompilasi” ke Rust, hasilnya menjadi Rust yang mengerikan, penuh dengan pemanggilan fungsi manipulasi pointer gaya C yang tidak aman
      Masalah pengangkatan terbesar sebagian besar berkaitan dengan pointer. Hasil paling menjanjikan dari makalah ini adalah ditemukannya cara mengubah aritmetika pointer C menjadi slice Rust. Slice bisa melakukan sebagian besar hal yang dilakukan aritmetika pointer C, dan sekarang seseorang telah mengotomatisasi terjemahan itu. Aritmetika pointer yang tidak bisa diterjemahkan seharusnya dipandang sangat mencurigakan
      Berguna jika Anda menganggap pointer mentah yang menunjuk ke array di C secara implisit memiliki panjang. Panjang itu tidak terlihat di sumber C, tetapi ada di suatu tempat sebagai fungsi dari state program. Bisa berupa konstanta, ukuran permintaan malloc, atau parameter fungsi. Bagi programmer pemeliharaan, biasanya tidak terlalu sulit menemukan panjang array
      Ini mungkin masalah yang cocok untuk LLM. Misalnya, tanyakan “lihat kode ini dan temukan berapa panjang array foo”, lalu biarkan penerjemah non-LLM memandu konversi Rust. Jika LLM salah, Rust akan menghasilkan kesalahan indeks atau memiliki array yang terlalu besar, tetapi tetap tidak menjadi tidak aman. Idiom informasi ukuran array di C cukup terstruktur sehingga sebagian besar kasus mestinya bisa ditebak dengan benar. Terutama karena LLM juga bisa membaca komentar
    • Terjemahan naif akan menghasilkan kode Rust yang hampir seluruhnya unsafe. Karena ia akan memakai pointer mentah di mana-mana alih-alih referensi
      Kode C tidak ditulis dengan mempertimbangkan model aliasing Rust dan batasan borrow checker, jadi sulit menerjemahkannya menjadi referensi
  • Ini hanya mengompilasi subset C yang sangat kecil. Dalam praktiknya, mungkin terlalu kecil sampai nyaris tidak berguna
    Ekspektasi terhadap pendekatan seperti ini rendah. Pasti akan menabrak batas dari apa yang bisa dilakukan dengan analisis statis kode C. Lagi pula, memilih Rust sebagai target membuat masalahnya jadi lebih sulit tanpa perlu. Model kepemilikan Rust terlalu berbeda dari cara program C nyata bekerja

    • Model kepemilikan Rust cukup dekat untuk menerjemahkan C. Hanya saja tipenya lebih eksplisit dan lebih kuat, jadi penerjemah harus memahami apa yang coba dilakukan kode C yang bebas lalu memetakannya ke idiom Rust
      Misalnya, buffer di C tentu punya panjang, tetapi di C panjang itu tidak secara eksplisit terikat pada pointer. Jadi penerjemah harus menyimpulkan bagaimana program C melacak panjangnya lalu mengubahnya menjadi slice. Bahkan jika panjangnya ada di variabel eksplisit pun tidak mudah, dan akan lebih rumit jika dihitung atau dinyatakan dalam bentuk “pointer satu langkah setelah akhir”
      Pola C seperti bool should_free_this_pointer juga bisa dipindahkan ke enum Owned/Borrowed di Rust, tetapi harus disimpulkan alokasi mana yang terhubung ke boolean mana, dan di mana batas aman yang sebenarnya untuk varian yang dipinjam
    • Ini mungkin bagus sebagai bahasa antarmuka. Berguna untuk binding
    • Pada akhirnya orang-orang tampaknya akan melempar LLM ke masalah ini, lalu bilang tidak apa-apa jika ia berhalusinasi menghasilkan banyak kode yang kelihatannya benar
      Meski begitu, saya setuju bahwa membuat Rust yang idiomatis dari C arbitrer akan sulit. Katakanlah hasilnya hanya akan “kurang lebih benar”
  • Saya penasaran bagaimana ini dibandingkan dengan fitur konversi C milik Zig
    Zig tampaknya unggul dalam menciptakan lingkungan campuran: kode baru ditulis dalam Zig, kode lama tetap di C, lalu dilakukan konversi atau interop, bahkan sekaligus berperan sebagai kompiler C
    Pasti ada alasan yang sangat bagus mengapa para maintainer kernel Linux tidak melihat Zig sebagai pengganti C alih-alih Rust. Saya tidak cukup paham untuk menebak, jadi akan bagus jika orang yang lebih tahu bisa menjelaskan

    • Rust bukan “pengganti C”, melainkan alat tambahan untuk C. Ini alat yang diakui nilainya oleh Torvalds dan lainnya sehingga diizinkan masuk ke kernel, dan sebagian besar kode kernel akan tetap ditulis dalam C
      Saya bukan maintainer kernel, tetapi jika menebak dua alasan besar Rust dipilih ketimbang Zig, mungkin karena jaminan saat kompilasi yang diberikan bahasanya lebih baik dan laju adopsinya juga lebih cepat
      Perusahaan-perusahaan besar di industri sedang banyak berupaya menyediakan kode native Rust untuk API atau binding Rust yang dipelihara. Para pengembang Windows juga sedang menulis ulang sebagian kernel mereka dalam Rust. Ini sudah menjadi gerakan yang berlangsung cukup lama, dan saya harap tidak berhenti
      Para maintainer mungkin merasa Zig tidak memberi cukup keuntungan dibanding C. Banyak dari mereka bahkan masih menentang Rust
    • Sepemahaman saya, sebagian besar maintainer kernel memang tidak berusaha mengganti C dengan apa pun
      Zig jauh lebih baik dalam interoperabilitas dengan C dibanding Rust, tetapi tidak aman memori dan juga belum stabil. Adopsi Zig di dunia C kemungkinan akan cukup meningkat, tetapi saya rasa sulit melihatnya sebagai pesaing langsung Rust
      Di daerah saya, tidak ada yang mengadopsi Rust, dan orang-orang C++ tetap bertahan di C++. Awalnya memang ada sedikit minat pada Rust, tetapi di perusahaan mana pun yang saya tahu, Rust tidak pernah benar-benar mapan. Mungkin alasannya mirip dengan Go yang tumbuh besar di perusahaan-perusahaan muda, tetapi tidak banyak masuk ke perusahaan Java/C# tradisional. Meskipun masuk akal secara teknis, ini adalah tantangan manajemen perubahan yang sangat besar
      Zig memang mendapat momentum untuk program yang tidak memerlukan alokasi memori dinamis, tetapi di luar itu tidak banyak
    • Zig belum cukup matang untuk dipertimbangkan masuk kernel
      Masih ada perubahan yang rutin mematahkan kompatibilitas, dan meskipun ini bagus untuk Zig saat ini, itu tidak baik untuk codebase raksasa dan berumur panjang seperti Linux. Bug kompiler juga masih muncul
      Saya bilang ini sebagai orang yang secara umum menyukai arah Zig
    • Zig belum mencapai 1.0 dan sama sekali tidak punya jaminan kompatibilitas mundur. Hampir tidak dipakai di mana pun, dan meskipun beberapa bagiannya terlihat menjanjikan, nilainya belum benar-benar terbukti
    • Mungkin juga karena Zig tidak aman memori
  • Saya penasaran apakah alat seperti C2Rust bisa memanfaatkan ini untuk menghasilkan kode yang benar secara formal
    Saya juga penasaran seberapa banyak pekerjaan manual yang dilakukan para penulis, atau apakah mereka menjalankan sesuatu untuk menghasilkan kode Rust. Jika ya, saya tidak tahu di mana kode yang menghasilkan Rust itu, dan saya juga tidak melihat tautan ke repositori sumbernya

    • Di makalahnya tertulis bahwa setelah proses review selesai, yakni kurang lebih setelah makalah tersebut resmi diterbitkan, hasil pengembangan ini akan dirilis dengan lisensi open source
  • Jika pustaka C-nya berfungsi, artinya bukan terbukti formal bebas masalah tetapi sebagian besar berjalan dengan baik, saya penasaran mengapa tidak menerjemahkannya memakai unsafe Rust
    Menurut saya ini tetap bernilai karena secara umum Rust masih kekurangan pustaka. Pada akhirnya ini tidak jauh berbeda dari memakai dll/so yang ditulis dalam C, yang dalam situasi tertentu juga bisa saja tidak aman