Saya benci compiler
(xeiaso.net)- Anubis sedang merancang perluasan proof-of-work perlindungan situs web melampaui SHA-256, agar klien dan server menjalankan logika verifikasi WebAssembly yang sama
- Untuk tidak mengecualikan lingkungan yang menonaktifkan WebAssembly, disiapkan jalur rekompilasi JavaScript, tetapi ini lebih lambat daripada WebAssembly dan bisa lebih lambat lagi jika JIT juga dinonaktifkan
wasm2jspada distribusi Linux sudah usang sehingga keluarannya berbeda dari versi Homebrew, dan demi build yang dapat direproduksi akhirnya dibundelwasm2jsyang dibangun dengan wasi-sdk- Build C/C++ dapat mengalami goyangan output tingkat byte meski inputnya sama, karena
__DATE__,__TIME__,wasm-optdi$PATH, dan urutan pointer pada kode penanganan exception - Implementasi akhir memastikan determinisme dalam arsitektur yang sama lewat
--no-wasm-opt,setarch --addr-no-randomize, verifikasi SHA-256 per x86_64 dan arm64, serta pemeriksaan rebuild di CI
Proof-of-work WebAssembly Anubis dan jalur pengganti JavaScript
- Anubis ingin menambahkan verifikasi proof-of-work berbasis WebAssembly agar administrator bisa memakai metode proof-of-work selain SHA-256 untuk melindungi situs web
- Tujuan utamanya adalah tidak mengimplementasikan logika verifikasi secara terpisah di klien dan server, melainkan mendefinisikannya hanya di satu tempat
- Klien dan server terhubung ke WebAssembly yang sama untuk menjalankan logika verifikasi
- Strukturnya diarahkan agar dapat memastikan keduanya berjalan lockstep
- Klien dengan WebAssembly yang dimatikan juga tetap dipertimbangkan
- Ada batasan bahwa pengguna tidak ingin secara efektif dikeluarkan dari situs web
- Anubis harus menyeimbangkan pengalaman pengguna, pengalaman admin, dan pengalaman pengembang
- Jalan memutar yang dipilih adalah mengompilasi ulang WebAssembly menjadi JavaScript
- Terinspirasi dari The Birth and Death of JavaScript
- JavaScript hasilnya lebih lambat daripada WebAssembly yang setara
- Menonaktifkan WebAssembly kadang juga menonaktifkan JavaScript JIT, sehingga bisa menjadi lebih lambat lagi
- Apakah ini lebih efisien daripada JavaScript yang sudah ada pada perangkat keras kelas bawah masih perlu penelitian tambahan
Mengapa wasm2js harus dibundel
- Alat yang dibutuhkan adalah
wasm2jsdari proyek binaryen wasm2jsmemang tersedia sebagai paket di distribusi Linux, tetapi versi distribusinya sudah terlalu lama dan tidak dapat menghasilkan output yang sama dengan versi Homebrew di lingkungan pengembangan- Build yang dapat direproduksi mensyaratkan determinisme output
- Agar pengguna dan pemaket bisa mempercayai biner
wasm2jsyang di-commit ke repositori Anubis, mereka harus bisa membangun versi yang sama sendiri dan mendapatkan byte yang sama - Kalau memungkinkan, byte yang sama juga harus keluar di mesin orang lain
- Agar pengguna dan pemaket bisa mempercayai biner
- Untuk itu, disertakan salinan
wasm2jsyang dibangun dengan wasi-sdk untuk target WebAssembly
Titik-titik tempat reproduktibilitas mudah rusak pada build C/C++
- Meski byte sumber dan inputnya sama, output compiler tidak selalu menjadi byte yang sama
- Di C/C++, makro bawaan seperti
__DATE__dan__TIME__saja sudah bisa menghasilkan output non-deterministik- Contoh
hello.cppditulis untuk mencetak tanggal dan waktu saat build - Satu build menghasilkan
Jun 18 2026 00:00:59, dan build lain menghasilkanJun 18 2026 00:01:11 - Byte kode sumbernya sama, tetapi output compilernya berbeda
- Contoh
- Pada compiler kecil, secara teoretis determinisme mungkin saja dicapai, tetapi compiler nyata memiliki jauh lebih banyak variabel kompleks
Masalah Clang yang diam-diam menjalankan wasm-opt dari $PATH
- Selain
wasm2js, binaryen juga memilikiwasm-optuntuk mengoptimalkan output compiler WebAssembly - Clang menjalankan
wasm-optlewat shell out selama proses build- Secara umum ini perilaku yang masuk akal untuk peningkatan performa
- Namun kali ini, perbedaan versi
wasm-optyang ada di$PATHmerusak reproduktibilitas
wasm-optdi DGX Spark adalah version 108 di/usr/bin/wasm-opt, sedangkanwasm-optHomebrew di workstation adalah version 130- wasi-sdk dan binaryen bergantung pada WebAssembly Exceptions extension
- Menurut Can I use, 93.86% pengguna browser memakai engine browser yang mendukungnya
- C++ adalah bahasa yang banyak menggunakan exception, jadi penanganan exception native WebAssembly dapat mengurangi boilerplate
- wasmtime dan wazero harus mengaktifkan dukungan exception secara eksplisit
- Pada wasmtime, bisa diberikan
-W exceptions=y - Pada wazero, diperlukan custom runner harness
- Pada wasmtime, bisa diberikan
wasm-optlama di mesin arm gagal build karena berhenti saat menemui instruksi penanganan exception- Dengan memberikan
--no-wasm-optpada tahap linking, jalur non-reproducible ini dihapus
Pengaruh tata letak alamat terhadap pembuatan kode penanganan exception
- Versi Clang yang digunakan menunjukkan pembuatan kode yang sensitif terhadap alamat pada jalur penanganan exception dalam proses kompilasi
wasm2js - Nilai pointer mentah memengaruhi urutan output beberapa blok
try_table- Per build muncul perbedaan sekitar 29 byte
- Perhitungannya nyaris sama, tetapi urutan bytenya berubah dan referensi catch juga berubah
- Bahkan saat membangun
wasm2jsdengan versi tetap yang sama di mesin arm64, urutan iterasi pointer berbeda dari workstation sehingga masalah yang sama tetap muncul - Ada dua solusi sementara
- Menonaktifkan pengacakan ruang alamat untuk build tersebut dengan
setarch --addr-no-randomize - Membuat checksum SHA-256 known-good untuk x86_64 dan arm64 masing-masing di mesin tepercaya
- Menonaktifkan pengacakan ruang alamat untuk build tersebut dengan
- CI menjalankan
./build.shdi./utils/wasm/wasm2jslalu memverifikasi checksum- Jika cocok dengan
shasums.x86_64, maka dianggap lulus checksum x86_64 - Jika cocok dengan
shasums.arm64, maka dianggap lulus checksum arm64 - Jika tidak cocok keduanya, CI mencetak SHA-256 dari
wasm-opt_130.wasmdanwasm2js_130.wasmlalu gagal
- Jika cocok dengan
- Tugas CI ini dijalankan di host x86_64 dan arm64
- Reproduksibilitas lintas seluruh host masih belum tercapai, dan masalah ini tetap menjadi bug LLVM upstream
- Dalam kondisi saat ini, setidaknya build sudah berjalan deterministik di dalam arsitektur yang sama
1 komentar
Pendapat di Lobste.rs
Ini pertama kalinya saya tahu
clangdiam-diam menjalankanwasm-optdi$PATH, dan menurut saya ini benar-benar tidak masuk akalKarena itu saya cek apakah ini juga memengaruhi
zig cc, dan untungnya tidak, karena itu hanya dijalankan saatclangdipakai sebagai driver linkerJika
clangmenentukan urutan berdasarkan tata letak alamat, saya pribadi menganggapnya sebagai bug, dan kalau masih bisa direproduksi di rilis terbaru, saya mungkin akan melaporkannya seperti ituUpaya untuk menghilangkan masalah seperti ini sudah berlangsung selama bertahun-tahun
clang.exesebagai cross-compiler yang andal di Windows itu bahkan lebih bikin gilaAda kira-kira 500 cara berbeda
clangberasumsi bahwa ia akan membangun untuk sistem nativeBukan mau mengkritik, dan saya menghormati fakta bahwa ini open source dan OP menyediakan layanan populer secara gratis
Meski begitu, saya benar-benar benci web berubah seperti ini. Sekarang makin sering tiap kali masuk ke situs web muncul halaman pemuatan Anubis yang menyala sekilas; saya tidak tahu apakah kita benar-benar menginginkan web di mana setiap situs populer menampilkan layar splash proof-of-work
Saya juga tidak tahu apa alternatifnya karena crawler AI terus berdatangan, tetapi saya juga ragu apakah ada bukti bahwa proof-of-work benar-benar menghentikan crawler AI. Mereka punya dana sangat besar, dan sudah melakukan komputasi yang jauh lebih besar hanya untuk membaca halaman, jadi biaya menyelesaikan proof-of-work tampak sangat kecil
Dalam pilot Anubis, ini jelas menjadi penangkal yang efektif terhadap trafik yang tidak diinginkan, dan dengan aturan yang nyaris default saja, sekitar 90% permintaan ke tiga aplikasi terus diblokir. Untuk DDR angkanya 71,0%, ArcLight 94,6%, dan Catalog 92,4%
Pada 30 Mei trafik bot melonjak, dan sampai Anubis diterapkan pada 3 Juni, katalog praktis tidak bisa melayani. Di puncaknya pada 1 Juni, ada 3,4 juta permintaan HTTP dari 2,1 juta IP unik, dan waktu muat halaman naik sampai lebih dari 70 detik. Setelah Anubis diterapkan pada 4 Juni, layanan kembali bisa diakses pengguna; total permintaan yang diproses aplikasi menjadi 125 ribu, dan waktu muat halaman membaik menjadi 2,12 detik
https://lobste.rs/s/ncyfcp/anubis_pilot_project_report_june_2025
Di kasus lain juga, masalahnya selesai tepat setelah Anubis dideploy, waktunya bisa terlihat jelas di monitoring, dan setelah itu tidak ada satu pun alert. Serangan tetap berlanjut, tetapi beban server berada di level minimum, jadi menurut saya Anubis bukan hanya memblokir scraper AI tetapi juga berfungsi sebagai perlindungan DDoS
https://lobste.rs/s/67ijih/day_anubis_saved_our_websites_from_ddos
https://orib.dev/tmp/bandwidth.png
Beberapa orang bahkan bisa memblokirnya hanya dengan tag
meta refreshatau tombol yang harus ditekan. Jadi Anubis memang bekerja, tetapi intinya bukan pada proof-of-work itu sendiri, melainkan pada perilaku yang tak terdugaIni terasa lebih menyiksa daripada masa ketika saya memakai web dengan browser yang JavaScript-nya dimatikan. Saya ingin web tetap berpusat pada dokumen, tetapi sekarang di mana-mana harus melewati gerbang Cloudflare, Anubis, atau captcha
Intinya, bot akan selalu menemukan cara untuk melewati WAF, sementara pengguna sungguhan akhirnya membuang siklus CPU di layar pemuatan
Disayangkan, tetapi tidak mengejutkan. Toolchain compiler punya sejarah panjang bergantung pada dependensi implisit yang absurd, semacam “konteks lokal harus benar begitu saja”
Meski begitu, LLVM justru termasuk pihak yang paling depan dalam menghapus dependensi semacam itu, jadi agak aneh melihat hal seperti ini di clang. Berkat itu, misalnya, compiler Rust bisa berjalan tanpa konsep cross-compiler terpisah
Ini langsung terlihat saat mencoba mem-bootstrap OS tanpa bergantung pada build tool yang sudah ada. Proses membuat kernel, lalu membuat libc dan compiler untuk kernel itu agar bisa berjalan, lalu membangun ulang semuanya di atas OS baru, adalah pekerjaan yang sangat rumit dan sensitif, penuh asumsi implisit yang tidak masuk akal
Karena ini masalah langka yang terutama hanya dialami pengembang OS dan compiler, hampir tidak ada alat yang bagus atau praktik terbaik, dan untuk tiap kombinasi compiler+OS rasanya mungkin hanya ada sekitar lima orang di dunia yang benar-benar memahami keseluruhannya
Saya juga mengira toolchain Zig mendapatkan sebagian kemampuan itu dari LLVM, meski saya paham mereka telah bekerja keras untuk memisahkannya dengan lebih rapi. Sekarang saya juga penasaran apakah mereka sudah tidak memakai LLVM lagi
Tapi kalau clang juga punya masalah yang sama, rasanya LLVM tidak benar-benar mewariskan struktur yang lebih bersih
Seingat saya Anda memakai Nix, jadi saya penasaran kenapa Nix tidak disebut atau dipakai untuk mengurangi setidaknya sebagian variabilitas lingkungan
Misalnya, masalah
wasm-optdi$PATHtampaknya bisa dimitigasi dengan Nix; atau sebenarnya sudah dipakai dan saya yang kelewatan?Secara naif saya pikir memindahkan wasm ke asm.js itu akan “mudah”, dan hari ini saya belajar hal baru
Judul blognya terasa seperti clickbait, tapi isinya bagus
Saya benar-benar benci clickbait