Chyba: container-overflow
Chyba sanitizátoru adresy: Přetečení kontejneru
V sadě Visual Studio 2022 verze 17.2 a novějších je standardní knihovna Microsoft Visual C++ (STL) částečně kompatibilní s addressSanitizerem. Následující typy kontejnerů mají poznámky k detekci problémů s přístupem k paměti:
Standardní typ kontejneru | Zakázat makro poznámek | Podporováno ve verzi |
---|---|---|
std::vector |
_DISABLE_VECTOR_ANNOTATION |
Visual Studio 2022 17.2 |
std::string |
_DISABLE_STRING_ANNOTATION |
Visual Studio 2022 17.6 |
Existují kontroly, které zajistí, že neexistují žádná porušení pravidla odr (one-definition-rule). K porušení odr dojde, když jedna jednotka překladu anotuje standardní typ, například vector
, s poznámkami ASan, ale jiná jednotka překladu ne. V tomto příkladu může linker současně zobrazit jednu deklaraci vector<int>::push_back
, která obsahuje poznámky sanitizátoru adres a jinou deklaraci vector<int>::push_back
, která není. Aby se tomuto problému zabránilo, musí každá statická knihovna a objekt použitý k propojení binárního souboru také povolit anotace ASan. V podstatě je nutné vytvořit tyto statické knihovny a objekty s povolenou addressSanitizer. Při kombinování kódu s různými nastaveními poznámek dojde k chybě:
my_static.lib(my_code.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '0' doesn't match value '1' in main.obj
Pokud chcete tuto chybu vyřešit, zakažte poznámky ve všech projektech, které používají odpovídající makro, nebo vytvořte každý projekt s povolenými /fsanitize=address
poznámkami a poznámkami. (Ve výchozím nastavení jsou povoleny poznámky.)
Příklad: Přístup k rezervované paměti v 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;
}
Pokud chcete tento příklad sestavit a otestovat, spusťte následující příkazy v sadě Visual Studio 2022 verze 17.2 nebo novějším okně příkazového řádku Developer:
cl /EHsc example1.cpp /fsanitize=address /Zi
devenv /debugexe example1.exe
Chyba výsledku vyhrazeného přístupu k paměti v std::vector
Vlastní alokátory a přetečení kontejneru
Kontroly přetečení kontejneru Sanitizer podporují nealokátorystd::allocator
. Vzhledem k tomu, že AddressSanitizer neví, jestli vlastní alokátor odpovídá požadavkům AddressSanitizer, jako je například sladění přidělení na 8 bajtových hranicích, nebo neumisťuje data mezi konec přidělení a další hranice 8 bajtů, nemusí být vždy schopna zkontrolovat, že přístupy na druhém konci přidělení jsou správné.
AddressSanitizer označuje bloky paměti v blocích 8 bajtů. Nemůže umístit nepřístupné bajty před přístupnými bajty v jednom bloku dat. Je platné mít 8 přístupných bajtů v bloku dat nebo 4 přístupné bajty následované 4 nepřístupnými bajty. Čtyři nepřístupné bajty nemohou následovat 4 přístupné bajty.
Pokud konec přidělení z vlastního alokátoru není striktně v souladu s koncem bloku 8 bajtů, addressSanitizer musí předpokládat, že alokátor provede bajty mezi koncem přidělení a koncem bloku dat dostupným pro alokátor nebo uživatele, do kterého se má zapisovat. Proto nemůže označit bajty v posledním 8 bajtovém bloku jako nepřístupný. V následujícím příkladu vector
, který přiděluje paměť pomocí vlastního alokátoru, odkazuje na neinicializovaná data a -, odkazuje na paměť, která je nepřístupná.
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
V předchozím příkladu má blok 3 4 bajty paměti, u které se předpokládá nedostupné, protože spadají mezi konec přidělení 20 bajtů, které byly vyhrazeny (v.reserve(20)
) a konec třetí logické seskupení 8 bajtů (pamatujte, že AddressSanitizer označuje bloky paměti v 8 bajtových blocích).
V ideálním případě bychom označili stínovou paměť, která sanitizátor adresuje každé 8 bajtové bloky paměti, abychom mohli sledovat, které bajty v tomto 8 bajtovém bloku jsou platné a které jsou neplatné (a proč), které v.data() + [0, v.size())
jsou přístupné a v.data() + [v.size(), v.capacity())
jsou nepřístupné. Všimněte si použití zápisu intervalu: "[" včetně a ")" se rozumí výhradně. Pokud uživatel používá vlastní alokátor, nevíme, jestli je paměť po v.data() + v.capacity()
přístupnosti nebo ne. Musíme předpokládat, že je to. Tyto bajty bychom raději označili jako nepřístupné ve stínové paměti, ale musíme je označit jako přístupné, aby po přidělení zůstaly dostupné.
std::allocator
používá statickou proměnnou _Minimum_asan_allocation_alignment
člena k určení vector
a string
že může důvěřovat alokátoru, aby neuložili data hned po přidělení. Tím zajistíte, že alokátor nebude používat paměť mezi koncem přidělení a koncem bloku dat. Proto může být část bloku dat označena nepřístupnou adresou Sanitizer pro zachycení přetečení.
Pokud chcete, aby implementace důvěřovala tomu, že váš vlastní alokátor zpracovává paměť mezi koncem přidělení a koncem bloku dat, aby mohl tuto paměť označit jako nepřístupnou a zachytit přetečení, nastavte _Minimum_asan_allocation_alignment
na skutečné minimální zarovnání. Aby AdresaSanitizer fungovala správně, musí být zarovnání alespoň 8.
Viz také
Přehled AddressSanitizer
Známé problémy s addressSanitizerem
Referenční dokumentace k sestavení a jazyku AddressSanitizer
Referenční informace k modulu runtime AddressSanitizer
Stínové bajty AddressSanitizer
AddressSanitizer – cloud nebo distribuované testování
Integrace ladicího programu AddressSanitizer
Příklady chyb AddressSanitizer