- Mengusulkan Tree Borrows, model memori baru untuk Rust yang mengatasi batas optimasi kode
unsafe
- Tree Borrows menyelesaikan masalah pendekatan Stacked Borrows yang tidak dapat mengizinkan berbagai pola yang sering dipakai dalam kode Rust dunia nyata dengan struktur pohon, sehingga memberikan aturan yang lebih realistis dan fleksibel
- Tree Borrows meloloskan 54% lebih banyak kasus uji kode dunia nyata dibandingkan Stacked Borrows
- Sambil tetap mempertahankan sebagian besar keamanan memori dan kemungkinan optimasi utama Rust, terutama read-read reordering, model ini juga mencerminkan fitur-fitur lanjutan dari borrow checker Rust modern
- Dengan memperkenalkan model mesin status berbasis pohon, pendekatan ini menjadi tonggak penting bagi riset optimasi Rust dan verifikasi keamanan
Sistem kepemilikan Rust dan batas kode unsafe
- Rust memberikan jaminan kuat seperti keamanan memori dan pencegahan data race melalui sistem tipe berbasis kepemilikan
- Namun Rust memiliki unsafe escape hatch, dan dalam kasus ini tanggung jawab verifikasi keamanan berpindah dari compiler ke pengembang
- Compiler ingin memanfaatkan aturan alias pointer untuk optimasi yang kuat, tetapi optimasi semacam ini bisa menjadi tidak efektif karena kode
unsafe yang salah
Stacked Borrows dan keterbatasannya
- Sebelumnya, model bernama Stacked Borrows digunakan untuk mendefinisikan 'perilaku yang salah' pada kode
unsafe dan memberikan acuan optimasi
- Namun pendekatan ini tidak dapat mengizinkan berbagai pola
unsafe yang umum dalam kode Rust nyata, dan juga tidak mencerminkan fitur borrow checker Rust yang diperkenalkan belakangan
Munculnya Tree Borrows
- Tree Borrows adalah model baru yang melacak izin memori dengan struktur pohon alih-alih struktur stack
- Dengan ini, model tersebut dapat mengizinkan lebih banyak pola kode Rust praktis secara aman, serta sangat meningkatkan fleksibilitas aturan borrow dan penerapannya di dunia nyata
- Dalam evaluasi terhadap 30.000 crate Rust populer, model ini meloloskan 54% lebih banyak kasus uji dibandingkan Stacked Borrows
Fitur dan keunggulan Tree Borrows
- Mempertahankan sebagian besar optimasi utama dari Stacked Borrows yang sudah ada, seperti read-read reorderings
- Selain itu, model ini juga dapat mencerminkan fitur lanjutan dari borrow checker Rust modern, seperti pola borrow yang tidak terstruktur dan manipulasi pointer yang kompleks
- Dengan memperkenalkan model mesin status berbasis pohon, model ini menyeimbangkan keamanan dan kemungkinan optimasi
Kesimpulan dan makna pentingnya
- Tree Borrows menghadirkan standar baru bagi penanganan kode
unsafe dan riset optimasi pada compiler Rust
- Model ini dinilai sebagai model memori yang realistis dan tangguh yang mencakup kode Rust praktis serta kebijakan borrow checker modern
- Makalah terkait, artefak, dan source code telah dipublikasikan, dan diperkirakan akan memberi pengaruh besar pada komunitas riset compiler Rust dan verifikasi
1 komentar
Pendapat Hacker News
Post blog terbaru dari Ralf Jung memberi konteks lebih banyak tautan
Bonus: presentasi terbaru dari kelompok riset yang mencoba menspesifikasikan semantik eksekusi Rust secara jelas dalam sebuah dialek Rust juga layak ditonton YouTube
Ada klaim bahwa dari sudut pandang compiler, jaminan kuat dari sistem tipe terkait pointer aliasing memungkinkan optimisasi yang kuat, tetapi saya penasaran seberapa efektif itu dalam praktik
Linus Torvalds sudah lama berargumen bahwa aturan strict aliasing di C tidak terlalu berguna dan malah menimbulkan masalah
Tulisan contohnya juga menarik
Saya penasaran apakah Rust pada dasarnya memang sangat berbeda dari C, tetapi dari pengalaman pribadi, terutama saat
unsafeterlibat, rasanya tidak terlalu berbedaSaya memang merasa aturan strict aliasing di C benar-benar buruk
Aturan yang diusulkan di Rust jauh berbeda, lebih berguna dari sudut pandang compiler, dan juga lebih ringan bebannya bagi programmer
Ada opt-out di dalam bahasa lewat penggunaan raw pointer, dan ada juga tool untuk memeriksa kode
Pada akhirnya, seperti semua desain bahasa, ini adalah kompromi
Rust tampaknya menemukan keseimbangan baru di area optimisasi ini, dan hasil penilaian itu akan terlihat seiring waktu
Aturan aliasing Rust sangat berbeda dari C
Di C, keyword
restrictpada dasarnya hanya bermakna untuk argumen fungsi, dan aliasing berbasis tipe (type-based aliasing) pada praktiknya jarang dipakai atau tidak nyaman digunakanDi Rust, lifetime dan mutabilitas bisa diekspresikan dengan rinci, dan memori bisa ditangani dengan aman lewat berbagai cara tanpa bergantung pada tipe itu sendiri
Hal besar lainnya adalah selama tidak ada referensi
&mutyang saling tumpang tindih, memori tetap bisa dimanfaatkan dengan membaginya menjadi beberapa&mutyang tidak overlapSaya ingin melihat analisis yang lebih luas tentang seberapa besar ini benar-benar memengaruhi performa
Cara sederhananya adalah menghapus seluruh bagian compiler yang menyampaikan informasi aliasing ke LLVM lalu membandingkan performanya
Ada juga klaim bahwa anotasi
noaliasmeningkatkan performa runtime sekitar 5%, dan ada komentar terkait itu (meski datanya sudah cukup lama)Sebaiknya pernyataan Linus tentang compiler dilihat dengan konteks yang tepat
Kernel OS dan compiler adalah domain yang sepenuhnya berbeda
Saat ini analisis alias memang menjadi inti peningkatan performa yang sangat kuat
Efek terbesar datang dari heuristik sederhana, sementara query alias yang kompleks sendiri kegunaannya tidak terlalu besar
Secara teoretis saya ingin menguji seberapa besar analisis alias yang sempurna bisa meningkatkan performa, tetapi untuk kode umum pun mungkin batasnya hanya sekitar 20%
Tentu saja ada batasan bahwa optimisasi yang sangat canggih (misalnya transformasi layout data) bahkan tidak akan dicoba tanpa analisis alias
Strict aliasing di C dan aliasing di Rust adalah konsep yang berbeda
C berfokus pada analisis berbasis tipe (TBAA), dan Rust memang sengaja tidak mengadopsinya
Ada thread lama terkait Stacked Borrows pada 2020 dan 2018
thread 2020
thread 2018
Saya pernah membaca spesifikasi Tree Borrows di situs Nevin beberapa tahun lalu, dan terkesan karena ia menyelesaikan masalah yang rumit dengan elegan
Dalam pengalaman nyata, Tree Borrows memungkinkan kode yang masuk akal tetapi tidak mungkin di Stacked Borrows
Contoh kode di pustaka standar Rust juga layak dilihat
Saya penasaran apakah Rust atau PL generasi berikutnya bisa berkembang hingga memungkinkan kita memilih di antara beberapa implementasi borrow checker dengan karakteristik dan tujuan berbeda, seperti kecepatan kompilasi, kecepatan runtime, fleksibilitas algoritme, dan sebagainya
Rust sebenarnya sudah mendukung pergantian implementasi borrow checker
Ia sudah berpindah dari yang berbasis scope ke non-lexical, dan ada juga implementasi eksperimental bernama Polonius sebagai opsi
Jika implementasi baru sudah siap, versi lama tidak perlu dipertahankan
Untuk fleksibilitas lebih besar, bisa juga memakai
Rc,RefCell, dan sebagainya yang membutuhkan pemeriksaan saat runtimeSudah ada banyak pendekatan seperti affine type (dipakai Rust), linear type, sistem efek, dependent type, pembuktian formal, dan lain-lain
Setiap pendekatan punya karakteristik berbeda dalam biaya implementasi, performa, pengalaman pengembangan, dan sebagainya
Di luar Rust juga ada kecenderungan mengejar kombinasi antara pengelolaan sumber daya otomatis yang produktif dan sistem tipe
Yang sebenarnya dibutuhkan adalah separation logic yang bisa menyatakan precondition fungsi secara presisi dan bahkan membuktikan kondisi perantara
Pendekatan Rust adalah mensistematisasikan invariant umum yang benar-benar diinginkan orang, sambil menjamin optimisasi yang kuat
Saya penasaran apakah hasil borrow checker memang hanya punya false negative dan tidak punya false positive
Kalau memang begitu, apakah mungkin menjalankan beberapa implementasi secara paralel dalam thread lalu memakai hasil dari yang paling cepat selesai
Mengizinkan banyak implementasi borrow checker sekaligus cenderung memecah ekosistem, jadi itu kurang diinginkan
Saya benar-benar menguji kode Rust di makalah itu, dan memastikan bahwa compiler stabil terbaru tidak menolaknya
Contoh kode:
Jika kode di atas dijalankan di miri, ia akan melaporkan error pada
*x = 10;, tetapiwrite(x);tidak memunculkan errorrustc dari sudut pandang sistem tipe tidak punya alasan menolak kedua versi itu karena
ybertipe*mutDi makalah itu, contoh berikut diberikan sebagai masalah pada kode
unsafe:Saya penasaran apakah ini benar-benar mungkin
Menggunakan beberapa referensi mutable ke variabel yang sama melalui pointer jelas merupakan UB, jadi saya merasa mungkin ada sesuatu yang saya salah pahami
Kode di atas melanggar aturan meskipun compiler Rust menerimanya
Aturan yang mana?
Kode yang lolos borrow checker adalah legal
unsafejuga bisa mengekspresikan hal yang ilegal/UBAda himpunan aturan yang lebih luas daripada cakupan borrow checker tetapi tetap legal
Riset ini bertujuan menetapkan batas itu secara ketat
Makalah Stacked Borrows lebih sederhana, tetapi punya keterbatasan terhadap kode
unsafenyata, sedangkan Tree Borrows mengakui rentang aman yang lebih luasJelas bahwa "beberapa pointer referensi mutable tidak bisa ada secara bersamaan", tetapi tidak ada penjelasan yang secara tegas menyebut aturan mana tepatnya yang dilanggar
Tree Borrows justru mengusulkan definisi seperti itu
Ungkapan seperti "kode bisa melakukan hal seperti ini" berarti bahwa jika Anda benar-benar membuat dan menjalankan kode itu, sesuatu memang akan terjadi, tetapi tanpa definisi seperti Tree Borrows, sulit menyediakan dasar yang jelas untuk menjelaskan kenapa itu salah
Sepertinya Anda sendiri juga sudah menerima perlunya aturan yang jelas seperti Tree Borrows
Kode
unsafeseperti itu memang benar-benar bisa dibuat, dan itulah yang membuatnya UBContoh: tautan playground
Jika ingin tahu konteks terkait, bagian awal paragraf berikutnya di makalah itu cukup jelas menunjukkan maksudnya
Ya, itu memang inti persoalannya
Sulit mematuhi aturan pelarangan beberapa referensi mutable, dan
unsafemencerminkan bahwa ia bisa mengizinkan jauh lebih banyak hal daripada yang dijamin oleh sistem lifetime RustSalah satu penulis, Neven Villani, adalah putra dari peraih Fields Medal 2010, Cédric Villani
Ini mengingatkan saya pada pepatah bahwa buah jatuh tidak jauh dari pohonnya
Dan saya juga ingin bercanda bahwa "qualities juga bisa dibilang dipinjam dari tree"
Saya juga pernah berkantor cukup dekat dengan ayahnya (peraih Fields Medal)
Itu sebelum ia terjun ke politik
Model ini benar-benar luar biasa
Saya berencana mengimplementasikannya juga di bahasa yang sedang saya buat
Mustahil ini déjà vu
Rasanya seperti melihat post ini terus muncul setiap 2–3 bulan sekali