Aracılığıyla paylaş


Hata: container-overflow

Adres Temizleme Hatası: Kapsayıcı taşması

Visual Studio 2022 sürüm 17.2 ve sonraki sürümlerinde, Microsoft Visual C++ standart kitaplığı (STL), AddressSanitizer ile çalışmak için kısmen aydınlatılır. Aşağıdaki kapsayıcı türlerinin bellek erişimi sorunlarını algılamak için ek açıklamaları vardır:

Standart kapsayıcı türü Ek açıklama makrolarını devre dışı bırakma Sürümde desteklenir
std::vector _DISABLE_VECTOR_ANNOTATION Visual Studio 2022 17.2
std::string _DISABLE_STRING_ANNOTATION Visual Studio 2022 17.6

Tek tanım kuralı (ODR) ihlali olmadığından emin olmak için denetimler vardır. ODR ihlali, bir çeviri birimi ASan ek açıklamalarıyla gibi vectorstandart bir türe açıklama eklediğinde oluşur, ancak başka bir çeviri birimi açıklama eklemez. Bu örnekte, bağlayıcı aynı anda adres dezenfektanı ek açıklamalarına sahip olan bir bildirimini vector<int>::push_back görebilir ve bunun başka bir bildirimi vector<int>::push_back yoktur. Bu sorunu önlemek için, ikiliyi bağlamak için kullanılan her statik kitaplığın ve nesnenin ASan ek açıklamalarını da etkinleştirmesi gerekir. Etkili bir şekilde, AddressSanitizer etkinken bu statik kitaplıkları ve nesneleri oluşturmanız gerekir. Kodun farklı ek açıklama ayarlarıyla karıştırılması hataya neden olur:

my_static.lib(my_code.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '0' doesn't match value '1' in main.obj

Bu hatayı düzeltmek için ilgili makroyu kullanan tüm projelerde ek açıklamaları devre dışı bırakın veya ve ek açıklamaları etkinleştirerek her projeyi /fsanitize=address derleyin. (Ek açıklamalar varsayılan olarak etkindir.)

Örnek: Bir içindeki ayrılmış belleğe erişme 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;
}

Bu örneği derlemek ve test etmek için Visual Studio 2022 sürüm 17.2 veya sonraki bir Geliştirici komut istemi penceresinde aşağıdaki komutları çalıştırın:

cl /EHsc example1.cpp /fsanitize=address /Zi
devenv /debugexe example1.exe

Bir içindeki ayrılmış bellek erişiminin hata sonucu std::vector

Screenshot of debugger displaying container-overflow error in example 1.

Özel ayırıcılar ve kapsayıcı taşması

Adres Dezenfektanı kapsayıcı taşması denetimleri ayırıcı olmayanlarıstd::allocator destekler. Ancak, AddressSanitizer özel ayırıcının 8 baytlık sınırlarda ayırmaları hizalama veya ayırmanın sonu ile sonraki 8 bayt sınırı arasına veri koymama gibi AddressSanitizer gereksinimlerine uygun olup olmadığını bilmediğinden, ayırmanın ikinci ucundaki erişimlerin doğru olup olmadığını her zaman denetleyemeyebilir.

AddressSanitizer, bellek bloklarını 8 baytlık öbeklerde işaretler. Erişilemeyen baytları erişilebilir baytlar önce tek bir öbekte yerleştiremez. Bir öbekte 8 erişilebilir bayt veya 4 erişilebilir bayt ve ardından 4 erişilemez bayt olması geçerlidir. Dört erişilemez bayt ve ardından 4 erişilebilir bayt eklenemez.

Özel ayırıcıdan ayırmanın sonu 8 baytlık öbeğin sonuyla kesin olarak uyumlu değilse, AddressSanitizer ayırıcının ayırmanın sonu ile öbek sonu arasındaki baytları ayırıcının veya kullanıcının yazması için kullanılabilir hale getirdiğini varsaymalıdır. Bu nedenle, son 8 baytlık öbekteki baytları erişilemez olarak işaretleyemez. '?' özel ayırıcı kullanarak bellek ayıran aşağıdaki örnekte vector başlatılmamış verileri, '-' ise erişilemeyen belleğe başvurur.

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

Önceki örnekte, 3. öbek, ayrılmış olan 20 bayt ayırmasının sonu (v.reserve(20)) ile 8 baytlık üçüncü mantıksal gruplandırma sonu arasında olduğundan erişilemez olduğu varsayılan 4 bayt belleğe sahiptir (AddressSanitizer'ın bellek bloklarını 8 baytlık öbeklerde işaretlediğini unutmayın).

İdeal olarak, Address Dezenfektanı'nın her 8 baytlık bellek bloğu için ayırdığı gölge belleği işaretleyerek bu 8 baytlık bloktaki hangi baytların geçerli olduğunu ve hangilerinin geçersiz (ve neden) olduğunu, bu nedenle v.data() + [0, v.size()) erişilebilir ve v.data() + [v.size(), v.capacity()) erişilemez olduğunu izleriz. Burada aralık gösteriminin kullanıldığına dikkat edin: '[' değeri dahil, ')' ise hariçtir. Kullanıcı özel ayırıcı kullanıyorsa, sonrasındaki belleğin v.data() + v.capacity() erişilebilir olup olmadığını bilmiyoruz. Öyle olduğunu varsaymalıyız. Bu baytları gölge bellekte erişilemez olarak işaretlemeyi tercih ederiz, ancak ayırmadan sonra bu baytlara erişmenin mümkün olması için bunları erişilebilir olarak işaretlememiz gerekir.

std::allocator statik üye değişkenini _Minimum_asan_allocation_alignment kullanarak ayırmadan hemen sonra veri koymaması için ayırıcıya güvenebileceklerini belirtir vectorstring . Bu, ayırıcının ayırmanın sonu ile öbek sonu arasındaki belleği kullanmamasını sağlar. Bu nedenle, öbek parçası aşırı çalıştırmaları yakalamak için Adres Temizleme tarafından erişilemez olarak işaretlenebilir.

Uygulamanın, özel ayırıcınızın ayırmanın sonu ile öbek sonu arasındaki belleği işleyip bu belleği erişilemez olarak işaretleyebileceğinden ve taşmaları yakalayabileceğinden emin olmasını istiyorsanız, gerçek minimum hizalamanıza ayarlayın _Minimum_asan_allocation_alignment . AddressSanitizer'ın düzgün çalışması için hizalamanın en az 8 olması gerekir.

Ayrıca bkz.

AddressSanitizer'a genel bakış
AddressSanitizer bilinen sorunları
AddressSanitizer derlemesi ve dil başvurusu
AddressSanitizer çalışma zamanı başvurusu
AddressSanitizer gölge baytları
AddressSanitizer bulut veya dağıtılmış test
AddressSanitizer hata ayıklayıcısı tümleştirmesi
AddressSanitizer hata örnekleri