Kesalahan: container-overflow
Kesalahan Pembersih Alamat: Luapan kontainer
Di Visual Studio 2022 versi 17.2 dan yang lebih baru, pustaka standar Microsoft Visual C++ (STL) sebagian dicerahkan untuk bekerja dengan AddressSanitizer. Jenis kontainer berikut memiliki anotasi untuk mendeteksi masalah akses memori:
Jenis kontainer standar | Menonaktifkan makro anotasi | Didukung dalam versi |
---|---|---|
std::vector |
_DISABLE_VECTOR_ANNOTATION |
Visual Studio 2022 17.2 |
std::string |
_DISABLE_STRING_ANNOTATION |
Visual Studio 2022 17.6 |
Ada pemeriksaan untuk memastikan bahwa tidak ada pelanggaran one-definition-rule (ODR). Pelanggaran ODR terjadi ketika satu unit terjemahan membuat anotasi jenis standar, seperti vector
, dengan anotasi ASan, tetapi unit terjemahan lain tidak. Dalam contoh ini, linker mungkin secara bersamaan melihat satu deklarasi vector<int>::push_back
yang memiliki anotasi pembersih alamat, dan deklarasi lain dari vector<int>::push_back
itu tidak. Untuk menghindari masalah ini, setiap pustaka statis dan objek yang digunakan untuk menautkan biner juga harus mengaktifkan anotasi ASan. Secara efektif, Anda harus membangun pustaka dan objek statis tersebut dengan AddressSanitizer diaktifkan. Mencampur kode dengan pengaturan anotasi yang berbeda menyebabkan kesalahan:
my_static.lib(my_code.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '0' doesn't match value '1' in main.obj
Untuk mengatasi kesalahan ini, nonaktifkan anotasi di semua proyek yang menggunakan makro terkait, atau buat setiap proyek menggunakan /fsanitize=address
dan anotasi diaktifkan. (Anotasi diaktifkan secara default.)
Contoh: Mengakses memori yang dipesan dalam std::vector
// Compile with: cl /EHsc /fsanitize=address /Zi
#include <vector>
int main() {
// Create a vector of size 10, but with a capacity of 20.
std::vector<int> v(10);
v.reserve(20);
// In versions prior to 17.2, MSVC ASan does NOT raise an exception here.
// While this is an out-of-bounds write to 'v', MSVC ASan
// ensures the write is within the heap allocation size (20).
// With 17.2 and later, MSVC ASan will raise a 'container-overflow' exception:
// ==18364==ERROR: AddressSanitizer: container-overflow on address 0x1263cb8a0048 at pc 0x7ff6466411ab bp 0x005cf81ef7b0 sp 0x005cf81ef7b8
v[10] = 1;
// Regardless of version, MSVC ASan DOES raise an exception here, as this write
// is out of bounds from the heap allocation.
v[20] = 1;
}
Untuk membuat dan menguji contoh ini, jalankan perintah berikut di jendela prompt perintah Visual Studio 2022 versi 17.2, atau yang lebih baru:
cl /EHsc example1.cpp /fsanitize=address /Zi
devenv /debugexe example1.exe
Kesalahan akibat akses memori yang dipesan dalam std::vector
Alokator kustom dan luapan kontainer
Pemeriksaan luapan kontainer Address Sanitizer mendukung non-alokatorstd::allocator
. Namun, karena AddressSanitizer tidak tahu apakah alokator kustom sesuai dengan persyaratan AddressSanitizer seperti menyelaraskan alokasi pada batas 8 byte, atau tidak menempatkan data di antara akhir alokasi dan batas 8 byte berikutnya, mungkin tidak selalu dapat memeriksa bahwa akses di akhir alokasi yang terakhir benar.
AddressSanitizer menandai blok memori dalam gugus 8 byte. Ini tidak dapat menempatkan byte yang tidak dapat diakses sebelum byte yang dapat diakses dalam satu gugus. Ini valid untuk memiliki 8 byte yang dapat diakses dalam gugus, atau 4 byte yang dapat diakses diikuti oleh 4 byte yang tidak dapat diakses. Empat byte yang tidak dapat diakses tidak dapat diikuti oleh 4 byte yang dapat diakses.
Jika akhir alokasi dari alokator kustom tidak secara ketat selaras dengan akhir gugus 8 byte, AddressSanitizer harus mengasumsikan bahwa alokator membuat byte antara akhir alokasi dan akhir gugus yang tersedia untuk alokator atau pengguna untuk menulis. Oleh karena itu, tidak dapat menandai byte dalam gugus 8 byte akhir sebagai tidak dapat diakses. Dalam contoh vector
berikut yang mengalokasikan memori menggunakan alokator kustom, '?' mengacu pada data yang tidak diinisialisasi dan '-' mengacu pada memori yang tidak dapat diakses.
std::vector<uint8_t, MyCustomAlloc<uint8_t>> v;
v.reserve(20);
v.assign({0, 1, 2, 3});
// the buffer of `v` is as follows:
// | v.data()
// | | v.data() + v.size()
// | | | v.data() + v.capacity()
// [ 0 1 2 3 ? ? ? ? ][ ? ? ? ? ? ? ? ? ][ ? ? ? ? - - - - ]
// chunk 1 chunk 2 chunk 3
Dalam contoh sebelumnya, gugus 3 memiliki 4 byte memori yang diasumsikan tidak dapat diakses karena berada di antara akhir alokasi 20 byte yang dicadangkan (v.reserve(20)
) dan akhir pengelompokan logis ketiga 8 byte (ingat bahwa AddressSanitizer menandai blok memori dalam gugus 8 byte).
Idealnya, kita akan menandai memori bayangan, yang disisihkan oleh Address Sanitizer untuk setiap blok memori 8 byte untuk melacak byte mana dalam blok 8 byte yang valid dan mana yang tidak valid (dan mengapa), sehingga v.data() + [0, v.size())
dapat diakses, dan v.data() + [v.size(), v.capacity())
tidak dapat diakses. Perhatikan penggunaan notasi interval di sini: '[' berarti termasuk, dan ')' berarti eksklusif. Jika pengguna menggunakan alokator kustom, kami tidak tahu apakah memori setelah v.data() + v.capacity()
dapat diakses atau tidak. Kita harus berasumsi bahwa itu. Kami lebih suka menandai byte tersebut sebagai tidak dapat diakses dalam memori bayangan, tetapi kita harus menandainya sebagai dapat diakses sehingga tetap mungkin untuk mengakses byte tersebut setelah alokasi.
std::allocator
_Minimum_asan_allocation_alignment
menggunakan variabel anggota statis untuk memberi tahu vector
dan string
bahwa mereka dapat mempercayai alokator untuk tidak menempatkan data tepat setelah alokasi. Ini memastikan bahwa alokator tidak akan menggunakan memori antara akhir alokasi dan akhir gugus. Dengan demikian, bagian dari gugus dapat ditandai tidak dapat diakses oleh Address Sanitizer untuk menangkap overruns.
Jika Anda ingin implementasi mempercayai bahwa alokator kustom Anda menangani memori antara akhir alokasi dan akhir gugus sehingga dapat menandai memori tersebut sebagai tidak dapat diakses dan menangkap overruns, diatur _Minimum_asan_allocation_alignment
ke penyelarasan minimum Anda yang sebenarnya. Agar AddressSanitizer berfungsi dengan benar, penyelarasan harus setidaknya 8.
Lihat juga
Gambaran umum AddressSanitizer
Masalah yang diketahui AddressSanitizer
Referensi bahasa dan build AddressSanitizer
Referensi runtime AddressSanitizer
Byte bayangan AddressSanitizer
AddressSanitizer cloud atau pengujian terdistribusi
Integrasi debugger AddressSanitizer
Contoh kesalahan AddressSanitizer