Runtime AddressSanitizer

Pustaka runtime AddressSanitizer mencegat fungsi dan operasi alokasi memori umum untuk memungkinkan inspeksi akses memori. Ada beberapa pustaka runtime berbeda yang mendukung berbagai jenis executable yang dapat dihasilkan pengkompilasi. Pengkompilasi dan linker secara otomatis menautkan pustaka runtime yang sesuai, selama Anda meneruskan opsi pada /fsanitize=address waktu kompilasi. Anda dapat mengambil alih perilaku default dengan menggunakan opsi pada /NODEFAULTLIB waktu tautan. Untuk informasi selengkapnya, lihat bagian tentang penautan dalam bahasa AddressSanitizer, build, dan referensi penelusuran kesalahan.

Saat mengkompilasi dengan cl /fsanitize=address, pengkompilasi menghasilkan instruksi untuk mengelola dan memeriksa byte bayangan. Program Anda menggunakan instrumentasi ini untuk memeriksa akses memori pada tumpukan, dalam tumpukan, atau dalam cakupan global. Pengkompilasi juga menghasilkan metadata yang menjelaskan tumpukan dan variabel global. Metadata ini memungkinkan runtime untuk menghasilkan diagnostik kesalahan yang tepat: nama fungsi, baris, dan kolom dalam kode sumber Anda. Dikompilasi, pemeriksaan kompilator dan pustaka runtime dapat dengan tepat mendiagnosis banyak jenis bug keamanan memori jika ditemui pada run-time.

Daftar pustaka runtime untuk menautkan ke runtime AddressSanitizer, pada Visual Studio 17.7 Pratinjau 3, berikut. Untuk informasi selengkapnya tentang /MT opsi (secara statis menautkan runtime) dan /MD (secara dinamis menautkan redist saat runtime), lihat opsi /MD, /MT, /LD (Gunakan Pustaka Run-Time).

Catatan

Dalam tabel berikut, {arch} adalah i386 atau x86_64. Pustaka ini menggunakan konvensi Clang untuk nama arsitektur. Konvensi MSVC biasanya x86 dan bukan i386 dan x64x86_64, tetapi mengacu pada arsitektur yang sama.

Opsi CRT Pustaka runtime AddressSanitizer (.lib) Biner runtime alamat (.dll)
/MT atau /MTd clang_rt.asan_dynamic-{arch}, clang_rt.asan_static_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MD atau /MDd clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}

Diagram berikut menunjukkan bagaimana pustaka runtime bahasa ditautkan untuk /MTopsi , , /MTd/MD, dan /MDd pengkompilasi:

Diagram bagaimana pustaka runtime ditautkan untuk berbagai opsi pengkompilasi.

Gambar menunjukkan tiga skenario untuk menautkan pustaka runtime. Yang pertama adalah /MT atau /MTd. My_exe.exe dan my_dll.dll keduanya ditampilkan dengan salinan VCRuntime yang ditautkan secara statis, Universal CRT, dan runtime C++. Skenario menunjukkan /MD di mana my_exe.exe dan my_dll.dll berbagi vcruntime140.dll, ucrtbase.dll, dan msvcp140.dll. Skenario terakhir menunjukkan /MDd di mana my_exe.exe dan my_dll.dll berbagi versi debug runtime: vcruntime140d.dll, ucrtbased.dll, dan msvcp140d.dll

Diagram berikut menunjukkan bagaimana pustaka ASan ditautkan untuk berbagai opsi pengkompilasi:

Diagram bagaimana dll runtime ASan ditautkan.

Gambar menunjukkan empat skenario untuk menautkan pustaka runtime ASan. Skenarionya adalah untuk /MT (secara statis menautkan runtime), /MTd (secara statis menautkan runtime debug), /MD (secara dinamis menautkan redist pada runtime), /MDd (secara dinamis menautkan redist debug saat runtime). Dalam semua kasus, my_exe.exe tautan dan rekannya my_dll.dll tautan ke satu instans clang-rt.asan-dynamix-x86_64.dll.

Bahkan ketika menautkan secara statis, DLL runtime ASan harus ada pada runtime--tidak seperti komponen C Runtime lainnya.

Versi sebelumnya

Sebelum Visual Studio 17.7 Pratinjau 3, build yang ditautkan secara statis (/MT atau /MTd) tidak menggunakan dependensi DLL. Sebagai gantinya, runtime AddressSanitizer secara statis ditautkan ke EXE pengguna. Proyek DLL kemudian akan memuat ekspor dari EXE pengguna untuk mengakses fungsionalitas ASan.

Proyek yang ditautkan secara dinamis (/MD atau /MDd) menggunakan pustaka dan DLL yang berbeda tergantung pada apakah proyek dikonfigurasi untuk debug atau rilis. Untuk informasi selengkapnya tentang perubahan ini dan motivasinya, lihat MSVC Address Sanitizer – One DLL untuk semua Konfigurasi Runtime.

Tabel berikut ini menjelaskan perilaku sebelumnya dari penautan pustaka runtime AddressSanitizer, sebelum Pratinjau Visual Studio 17.7 3:

Opsi CRT DLL atau EXE DEBUG? Pustaka ASan (.lib) Biner runtime ASan (.dll)
/MT EXE No clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch} Tidak
/MT DLL No clang_rt.asan_dll_thunk-{arch} Tidak
/MD Baik No clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MT EXE Ya clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch} Tidak
/MT DLL Ya clang_rt.asan_dbg_dll_thunk-{arch} Tidak
/MD Baik Ya clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch} clang_rt.asan_dbg_dynamic-{arch}

Diagram berikut menunjukkan bagaimana pustaka ASan ditautkan untuk berbagai opsi pengkompilasi sebelum Visual Studio 2022 17.7 Pratinjau 3:

Diagram bagaimana dll runtime ASan ditautkan sebelum Visual Studio 2022 Pratinjau 3.

Gambar menunjukkan empat skenario untuk menautkan pustaka runtime ASan. Skenarionya adalah untuk /MT (secara statis menautkan runtime), /MTd (secara statis menautkan runtime debug), /MD (secara dinamis menautkan redist pada runtime), /MDd (secara dinamis menautkan redist debug saat runtime). Untuk /MT, my_exe.exe memiliki salinan runtime ASan yang ditautkan secara statis. my_dll.dll tautan ke runtime ASan di my_exe.exe. Untuk /MTd, diagramnya sama kecuali menggunakan runtime ASan yang ditautkan secara statis debug. Untuk /MD, baik tautan my_exe.exe dan my_dll.dll ke runtime ASan yang ditautkan secara dinamis bernama clang_rt.asan_dynamic-x86_64.dll. Untuk /MDd, diagramnya sama kecuali tautan my_exe.exe dan my_dll.dll ke runtime ASan debug bernama clang_rt.asan_dbg_dynamic-x86_64.dll.

Intersepsi fungsi

AddressSanitizer mencapai intersepsi fungsi melalui banyak teknik hotpatching. Teknik ini paling baik didokumenkan dalam kode sumber itu sendiri.

Pustaka runtime mencegat banyak manajemen memori umum dan fungsi manipulasi memori. Untuk daftar, lihat Daftar AddressSanitizer fungsi yang disadap. Pencegat alokasi mengelola metadata dan byte bayangan yang terkait dengan setiap panggilan alokasi. Setiap kali fungsi CRT seperti malloc atau delete dipanggil, pencegat menetapkan nilai tertentu di wilayah memori bayangan AddressSanitizer untuk menunjukkan apakah lokasi timbunan tersebut saat ini dapat diakses dan apa batas alokasinya. Byte bayangan ini memungkinkan pemeriksaan byte bayangan yang dihasilkan kompilator untuk menentukan apakah beban atau penyimpanan valid.

Intersepsi tidak dijamin berhasil. Jika prolog fungsi terlalu singkat untuk jmp ditulis, penyadapan dapat gagal. Jika kegagalan intersepsi terjadi, program akan melempar debugbreak dan menghentikan. Jika Anda melampirkan debugger, itu membuat penyebab masalah intersepsi menjadi jelas. Jika Anda memiliki masalah ini, laporkan bug.

Catatan

Pengguna dapat secara opsional mencoba untuk melanjutkan melewati intersepsi yang gagal dengan mengatur variabel ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE lingkungan ke nilai apa pun. Melanjutkan melewati kegagalan intersepsi dapat mengakibatkan laporan bug yang terlewat untuk fungsi tersebut.

Alokator kustom dan runtime AddressSanitizer

Runtime AddressSanitizer menyediakan pencegat untuk antarmuka alokator umum, , malloc/free, newdeleteHeapFreeHeapAlloc//(melalui ).RtlAllocateHeap/RtlFreeHeap Banyak program menggunakan alokator kustom karena satu alasan atau lainnya, contohnya adalah program apa pun yang menggunakan dlmalloc atau solusi menggunakan std::allocator antarmuka dan VirtualAlloc(). Pengkompilasi tidak dapat secara otomatis menambahkan panggilan manajemen memori bayangan ke alokator kustom. Pengguna bertanggung jawab untuk menggunakan antarmuka keracunan manual yang disediakan. API ini memungkinkan alokator ini berfungsi dengan baik dengan runtime AddressSanitizer yang ada dan konvensi byte bayangan.

Antarmuka keracunan AddressSanitizer Manual

Antarmuka untuk pencerahan sederhana, tetapi memberlakukan pembatasan penyelarasan pada pengguna. Pengguna dapat mengimpor prototipe ini dengan mengimpor sanitizer/asan_interface.h. Berikut adalah prototipe fungsi antarmuka:

void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);

Untuk kenyamanan, file header antarmuka AddressSanitizer menyediakan makro pembungkus. Makro ini memeriksa apakah fungsionalitas AddressSanitizer diaktifkan selama kompilasi. Mereka memungkinkan kode sumber Anda untuk menghilangkan panggilan fungsi keracunan saat tidak diperlukan. Makro ini harus lebih disukai daripada memanggil fungsi di atas secara langsung:

#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)

Persyaratan penyelarasan untuk keracunan AddressSanitizer

Setiap keracunan manual byte bayangan harus mempertimbangkan persyaratan penyelarasan. Pengguna harus menambahkan padding jika perlu sehingga byte bayangan berakhir pada batas byte dalam memori bayangan. Setiap bit dalam memori bayangan AddressSanitizer mengodekan status byte tunggal dalam memori aplikasi. Pengodean ini berarti ukuran total setiap alokasi, termasuk padding apa pun, harus selaras dengan batas 8 byte. Jika persyaratan penyelarasan tidak terpenuhi, persyaratan tersebut dapat menyebabkan pelaporan bug yang salah. Pelaporan yang salah dapat bermanifestasi sebagai laporan yang hilang (negatif palsu) atau laporan tentang non-kesalahan (positif palsu).

Untuk ilustrasi persyaratan perataan dan potensi masalah, lihat contoh perataan ASan yang disediakan. Salah satunya adalah program kecil untuk menunjukkan apa yang bisa salah dengan keracunan memori bayangan manual. Yang kedua adalah contoh implementasi keracunan manual menggunakan std::allocator antarmuka.

Opsi run-time

Microsoft C/C++ (MSVC) menggunakan runtime berdasarkan runtime Clang AddressSanitizer dari repositori llvm-project. Karena itu, sebagian besar opsi runtime dibagikan antara dua versi. Daftar lengkap opsi runtime Clang publik tersedia di sini. Kami mendokumen beberapa perbedaan di bagian berikut. Jika Anda menemukan opsi yang tidak berfungsi seperti yang diharapkan, laporkan bug.

Opsi AddressSanitizer yang tidak didukung

  • detect_container_overflow
  • unmap_shadow_on_exit

Catatan

Opsi halt_on_error runtime AddressSanitizer tidak berfungsi seperti yang mungkin Anda harapkan. Dalam pustaka runtime Clang dan MSVC, banyak jenis kesalahan dianggap tidak dapat dilanjutkan, termasuk sebagian besar kesalahan kerusakan memori.

Untuk informasi selengkapnya, lihat bagian Perbedaan dengan Clang 12.0 .

Opsi runtime AddressSanitizer khusus MSVC

  • windows_hook_legacy_allocators Boolean, atur ke false untuk menonaktifkan intersepsi GlobalAlloc dan LocalAlloc alokator.

    Catatan

    Opsi windows_hook_legacy_allocators ini tidak tersedia di runtime proyek llvm publik saat artikel ini ditulis. Opsi pada akhirnya dapat dikontribusikan kembali ke proyek publik; namun, itu tergantung pada tinjauan kode dan penerimaan komunitas.

    Opsi windows_hook_rtl_allocators, sebelumnya fitur keikutsertaan saat AddressSanitizer bersifat eksperimental, sekarang diaktifkan secara default. Dalam versi sebelum Visual Studio 2022 versi 17.4.6, nilai opsi defaultnya adalah false. Di Visual Studio 2022 versi 17.4.6 dan versi yang lebih baru, opsi windows_hook_rtl_allocators default ke true.

  • iat_overwrite String, diatur ke "error" secara default. Nilai lain yang mungkin adalah "protect" dan "ignore". Beberapa modul dapat menimpa import address table modul lain untuk menyesuaikan implementasi fungsi tertentu. Misalnya, driver biasanya menyediakan implementasi kustom untuk perangkat keras tertentu. Opsi iat_overwrite mengelola perlindungan runtime AddressSanitizer terhadap penimpaan untuk fungsi tertentu memoryapi.h . Runtime saat ini melacak VirtualAllocfungsi , VirtualProtect, dan VirtualQuery untuk perlindungan. Opsi ini tersedia di Visual Studio 2022 versi 17.5 Pratinjau 1 dan versi yang lebih baru. Nilai berikut iat_overwrite mengontrol bagaimana runtime bereaksi saat fungsi yang dilindungi ditimpa:

    • Jika diatur ke "error" (default), runtime melaporkan kesalahan setiap kali penimpaan terdeteksi.
    • Jika diatur ke "protect", runtime mencoba menghindari penggunaan definisi yang ditimpa dan melanjutkan. Secara efektif, definisi asli memoryapi fungsi digunakan dari dalam runtime untuk menghindari rekursi tak terbatas. Modul lain dalam proses masih menggunakan definisi yang ditimpa.
    • Jika diatur ke "ignore", runtime tidak mencoba memperbaiki fungsi yang ditimpa dan melanjutkan eksekusi.
  • windows_fast_fail_on_error Boolean (false secara default), atur ke true untuk mengaktifkan proses untuk mengakhiri dengan __fastfail(71) setelah mencetak laporan kesalahan.

Catatan

Ketika nilai abort_on_error diatur ke true, pada Windows program berakhir dengan exit(3). Agar tidak mengubah perilaku saat ini, kami memutuskan untuk memperkenalkan opsi baru ini sebagai gantinya. Jika abort_on_error dan windows_fast_fail_on_error benar, program akan keluar dengan __fastfail.

Daftar AddressSanitizer dari fungsi yang dicegat (Windows)

Runtime AddressSanitizer melakukan hotpatch pada banyak fungsi untuk mengaktifkan pemeriksaan keamanan memori pada runtime. Berikut adalah daftar fungsi yang tidak lengkap yang dipantau runtime AddressSanitizer.

Pencegat default

Pencegat opsional

Pencegat yang tercantum di sini hanya diinstal ketika opsi runtime AddressSanitizer diaktifkan. Atur windows_hook_legacy_allocators ke false untuk menonaktifkan intersepsi alokator warisan. set ASAN_OPTIONS=windows_hook_legacy_allocators=false

Lihat juga

Gambaran umum AddressSanitizer
Masalah yang diketahui AddressSanitizer
Referensi bahasa dan build AddressSanitizer
Byte bayangan AddressSanitizer
AddressSanitizer cloud atau pengujian terdistribusi
Integrasi debugger AddressSanitizer
Contoh kesalahan AddressSanitizer