Udostępnij przez


Bajty w tle addressSanitizer

Krótko podsumujemy koncepcję bajtów w tle i sposobu ich użycia przez implementację środowiska uruchomieniowego programu /fsanitize=address. Aby uzyskać więcej informacji, zapoznajmy się z papierem przełomowym i algorytmem AddressSanitizer.

Podstawowa koncepcja

Co 8 bajtów w wirtualnej przestrzeni adresowej aplikacji można opisać przy użyciu jednego bajtu w tle.

Jeden bajt w tle opisuje, ile bajtów jest obecnie dostępnych w następujący sposób:

  • 0 oznacza wszystkie 8 bajtów
  • 1–7 oznacza od jednego do siedmiu bajtów
  • Liczby ujemne kodują kontekst środowiska uruchomieniowego do użycia na potrzeby diagnostyki raportowania.

Legenda bajtów cienia

Rozważmy tę legendę bajtów w tle, w której zdefiniowano wszystkie liczby ujemne:

Screenshot of the AddressSanitizer shadow-byte legend.

Mapowanie — opisywanie przestrzeni adresowej

Co 8 bajtów w wirtualnej przestrzeni adresowej aplikacji, która jest wyrównana "0-mod-8", można zamapować na bajt w tle, który opisuje to miejsce w wirtualnej przestrzeni adresowej. To mapowanie można wykonać za pomocą prostego przesunięcia i dodania.

W systemie x86:

char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)

Na x64:

char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)

Generowanie kodu — testy

Zastanów się, w jaki sposób określone bajty w tle mogą być zapisywane przez kod wygenerowany przez kompilator, dane statyczne lub środowisko uruchomieniowe. Ten pseudo-kod pokazuje, jak można wygenerować kontrolę poprzedzającą wszelkie obciążenia lub magazyn:

ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
    ReportAndCrash(Addr);
}

Instrumentacja w przypadku instrumentacji odwołania do pamięci, która jest mniejsza niż 8 bajtów, instrumentacja jest nieco bardziej złożona. Jeśli wartość cienia jest dodatnia (co oznacza, że można uzyskać dostęp tylko do pierwszych k bajtów w 8-bajtowym słowie), musimy porównać ostatnie 3 bity adresu z k.

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
    ReportAndCrash(Addr);
}

Środowisko uruchomieniowe i kod wygenerowany przez kompilator zapisują bajty w tle. Te bajty w tle zezwalają na dostęp lub odwoływanie dostępu, gdy zakresy kończą się lub są zwalniane. Powyższe kontrole odczytują bajty w tle, które opisują 8-bajtowe "gniazda" w przestrzeni adresowej aplikacji w określonym czasie wykonywania programu. Oprócz tych jawnie wygenerowanych kontroli środowisko uruchomieniowe sprawdza również bajty w tle po przechwyceniu (lub "hakach") wielu funkcji w CRT.

Aby uzyskać więcej informacji, zobacz listę przechwyconych funkcji.

Ustawianie bajtów w tle

Zarówno kod generowany przez kompilator, jak i środowisko uruchomieniowe AddressSanitizer może zapisywać bajty w tle. Na przykład kompilator może ustawić bajty w tle, aby zezwolić na stały dostęp do stosu ustawień lokalnych zdefiniowanych w zakresie wewnętrznym. Środowisko uruchomieniowe może otaczać zmienne globalne w sekcji danych z bajtami w tle.

Zobacz też

AddressSanitizer — omówienie
Rozwiązywanie znanych problemów z programemSanitizer
Dokumentacja języka i kompilacji narzędzia AddressSanitizer
AddressSanitizer runtime reference (Dokumentacja środowiska uruchomieniowego AddressSanitizer)
AddressSanitizer — chmura lub testowanie rozproszone
Integracja debugera AddressSanitizer
Przykłady błędów addressSanitizer