- Setelah sebelumnya menghapus
strncpy() dari proyek, cURL kini melarang strcpy() sepenuhnya dari codebase
- API
strcpy() memang sederhana, tetapi ada risiko validasi ukuran buffer terpisah sehingga tidak aman untuk pemeliharaan jangka panjang
- Sebagai gantinya, diperkenalkan fungsi baru bernama
curlx_strcopy() yang menerima ukuran buffer tujuan dan panjang string sebagai argumen, lalu memeriksa apakah penyalinan aman sebelum dijalankan
- Fungsi ini secara internal menggunakan
memcpy() dan menjamin penanganan karakter null terminator
- Perubahan ini dapat meningkatkan keamanan dan konsistensi kode, sekaligus mengurangi masalah AI yang menghasilkan laporan kerentanan yang keliru
Latar belakang penghapusan strcpy
- cURL sebelumnya telah menghapus seluruh pemanggilan
strncpy(), sambil menyoroti masalah API yang tidak intuitif, kegagalan menjamin null terminator, dan 0 padding yang tidak perlu
- Untuk kasus yang memerlukan penyalinan substring, pendekatannya diubah menjadi menggunakan
memcpy() dan menangani null terminator secara manual
- API
strcpy() memang sederhana, tetapi karena tidak menyatakan ukuran buffer secara eksplisit, ada risiko kode validasi dan pemanggilan penyalinan terpisah saat pemeliharaan
- Jika kode dimodifikasi selama puluhan tahun oleh banyak pengembang, ada kemungkinan validasi ukuran buffer menjadi tidak efektif
Pengenalan fungsi penyalin string baru
- Untuk mencegah risiko tersebut, diperkenalkan fungsi pengganti bernama
curlx_strcopy()
- Argumennya adalah buffer tujuan, ukuran buffer, buffer sumber, dan panjang string sumber
- Penyalinan dengan
memcpy() hanya dilakukan jika penyalinan dan null termination sama-sama memungkinkan
- Jika gagal, buffer tujuan diinisialisasi sebagai string kosong
- Fungsi ini memang membutuhkan lebih banyak argumen dan lebih banyak kode dibanding
strcpy(), tetapi mengaitkan validasi buffer dengan proses penyalinan secara erat untuk menjamin keamanan
- Penggunaan
strcpy() kini dilarang sepenuhnya di codebase cURL, sama seperti strncpy() yang telah lebih dulu dihapus
Detail implementasi
- Contoh definisi fungsi adalah sebagai berikut
void curlx_strcopy(char *dest, size_t dsize, const char *src, size_t slen)
{
DEBUGASSERT(slen < dsize);
if(slen < dsize) {
memcpy(dest, src, slen);
dest[slen] = 0;
}
else if(dsize)
dest[0] = 0;
}
DEBUGASSERT dipakai untuk mendeteksi kesalahan lebih awal selama pengembangan, dan dirancang agar selalu berhasil di lingkungan rilis aktual
- Seperti
strcpy, fungsi ini tidak memiliki nilai balik, dan memakai pendekatan menangkap kesalahan pada tahap pengujian dan fuzzing
Reaksi komunitas
- Sebagian pengembang menilai ini mirip dengan
strcpy_s() (C11 Annex K), tetapi cURL masih menggunakan standar C89
- Ada juga masukan lain seperti perlunya nilai balik atau perbaikan penanganan saat buffer gagal
- Menanggapi hal itu, pihak cURL menjelaskan bahwa “karena fungsi ini dirancang agar selalu berhasil, nilai balik tidak diperlukan”
Efek tambahan terkait AI
- Perubahan ini juga dapat mencegah chatbot AI salah mendeteksi penggunaan strcpy di kode cURL lalu mengklaimnya ‘rentan’
- Namun, penulis tetap menyebut bahwa “AI masih mungkin menghasilkan laporan palsu lainnya”, sambil menyinggung batasan analisis kode berbasis AI
5 komentar
Benar, yang tepat adalah menggunakan
snprintfalih-alihstrcpy. Kalau adastrcpydi dalam kode, kita perlu mencari tahu alamat pengembang yang membuatnya.Itu adalah cara yang dulu saya kerjakan sebagai kode debug saat bekerja di perusahaan game 25 tahun lalu, dan tentu bukan cuma
strcpysaja. Saat rilis, itu kembali dilonggarkan demi peningkatan kecepatan lalu dipakai dalam layanan. Sebenarnya, di bidang game benturan memori adalah hal yang paling sensitif, jadi pengerjaannya juga dilakukan dengan sangat hati-hati dan penuh kewaspadaan; kami bahkan membuat dan memakai debugger memori sendiri. Tapi ketika melihatnya sekarang, ternyata kami waktu itu sedang membuat garbage collection. Kenangan yang samar dan manis.Error C4996
'strcpy': Fungsi atau variabel ini mungkin tidak aman. Pertimbangkan untuk menggunakanstrcpy_ssebagai gantinya. Untuk menonaktifkan deprecation, gunakan_CRT_SECURE_NO_WARNINGS. Lihat bantuan online untuk detailnya.Komentar Hacker News
strcpy() tidak baik bukan hanya dari sisi keamanan, tetapi juga dari sisi performa
Dulu orang menganggap strcpy() efisien saat panjang string tidak diketahui, tetapi pada praktiknya ia menyalin satu byte demi satu byte sehingga CPU harus melakukan prediksi cabang, dan ini tidak efisien
Rutinitas string di C semuanya terasa tidak berguna karena masing-masing punya keterbatasan besar
Karena itu saya merasa benar-benar dibutuhkan pustaka yang, bersama pointer string, juga mencatat ukuran memori yang dialokasikan
Sebagai contoh, pustaka bstring layak dijadikan referensi
char username[20]dengan padding NUL. Lihat dokumentasi terkait di manual string_copying.7Agak aneh bahwa curlx_strcopy tidak mengembalikan status berhasil atau tidak
Kita memang bisa memeriksa dest[0], tetapi ini sangat mudah memicu kesalahan dan tidak intuitif
DEBUGASSERT(slen < dsize);dianggap sebagai tanda sukses jika lolos, tetapi pada build release assert bisa dihapus. Saya rasa kode error yang eksplisit lebih baikstrncpy() pada awalnya bukan untuk string null-terminated, melainkan untuk field berpanjang tetap
Masalahnya bermula ketika penganalisis statis merekomendasikan penggunaan strncpy sebagai pengganti strcpy. Padahal alternatif yang sebenarnya adalah snprintf atau strlcpy
API ini terasa seperti Annex-K. Ruang NUL dihitung dalam ukuran buffer tujuan, tetapi tidak dihitung dalam ukuran sumber
Saya malah merasa lebih baik menulis memcpy secara langsung
Kalimat dalam artikel bahwa “strcpy adalah umpan yang membuat AI menghasilkan laporan kerentanan yang salah” sangat membekas
Prinsip “periksa di dekat kode” itu bagus, tetapi menjadi rancu saat kita perlu memeriksa di awal siklus hidup data
Akan bagus jika, seperti tipe Result di Rust, kita bisa membedakan lewat tipe bahwa ini adalah “data yang sudah tervalidasi”
Perbedaan off-by-one antara ukuran buffer dan panjang string adalah masalah kegunaan yang mengerikan. Sangat mungkin terus memicu kesalahan ke depannya
Fungsi penyalinan string yang baru diusulkan akan mengosongkan buffer tujuan dan mengembalikan void jika penyalinan tidak memungkinkan
Tetapi saya rasa dalam kasus seperti ini, lebih baik diperlakukan sebagai error dan buffer tidak disentuh. Mengandalkannya hanya pada DEBUGASSERT terasa tidak aman
Selamat menyelesaikan proyeknya. C/C++ pun, jika diupayakan, bisa mendapatkan keamanan memori
Namun di lingkungan mobile, ukuran font grafik terlalu kecil sehingga keterbacaannya menurun
Beralih sepenuhnya ke bahasa C3 juga bagus. Ini adalah proyek yang mempertahankan sintaks bahasa C dengan perubahan seminimal mungkin sambil menambahkan fitur-fitur modern, jadi migrasinya juga mudah.