Ten dokument pokazuje, jak włączyć specjalne narzędzia debugowania podczas korzystania z AGDE. Te narzędzia mogą pomóc w diagnozowaniu trudnych do wykrycia błędów związanych z uszkodzonymi pamięciami i błędami nadpisywania.
HWAddress Sanitizer i Address Sanitizer
HWAddress Sanitizer (HWASan) i Address Sanitizer (ASan) to narzędzia do debugowania uszkodzeń pamięci, które ułatwiają debugowanie uszkodzeń pamięci i błędów zastępowania, takich jak:
- Przepełnienie i niepełne wypełnienie bufora stosu
- Przepełnienie i niewykorzystanie bufora stosu
- Używanie pakietu poza jego zakresem
- Błędy związane z podwójnym i dzikim wolnym
- Użycie stosu po powrocie (dotyczy tylko HWASan)
Zalecamy włączenie HWASan lub ASan tylko wtedy, gdy debugujesz problem lub wykonujesz automatyczne testy. Chociaż te narzędzia są wydajne, ich używanie wiąże się z sankcją.
Zachowanie w środowisku wykonawczym
Po włączeniu zarówno HWASan, jak i ASan automatycznie sprawdzają, czy w aplikacji nie doszło do uszkodzenia pamięci.
Jeśli zostanie wykryty błąd pamięci, aplikacja ulegnie awarii z błędem SIGBART
(zatrzymanie sygnału) i wyświetli szczegółowy komunikat w logcat. Kopia wiadomości jest również zapisywana w pliku w folderze /data/tombstones
.
Komunikat o błędzie wygląda mniej więcej tak:
ERROR: HWAddressSanitizer: tag-mismatch on address 0x0042a0826510 at pc 0x007b24d90a0c
WRITE of size 1 at 0x0042a0826510 tags: 32/3d (ptr/mem) in thread T0
#0 0x7b24d90a08 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x2a08)
#1 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
#2 0x7b8f1db364 (/apex/com.android.art/lib64/libart.so+0x18f364)
#3 0x7b8f2ad8d4 (/apex/com.android.art/lib64/libart.so+0x2618d4)
0x0042a0826510 is located 0 bytes to the right of 16-byte region [0x0042a0826500,0x0042a0826510)
allocated here:
#0 0x7b92a322bc (/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so+0x212bc)
#1 0x7b24d909e0 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x29e0)
#2 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
Wymagania wstępne
Wymagania dotyczące HWASan
Aby korzystać z HWASan:
- Musisz używać AGDE 24.1.99 lub nowszej wersji.
- Aplikacja musi być skompilowana za pomocą NDK 26 lub nowszej wersji.
- Aplikacja musi być skompilowana z pakietem SDK w wersji 34 lub nowszej.
- Docelowe urządzenie
arm64-v8a
musi mieć Androida 14 (API na poziomie 34) lub nowszego.
Korzystanie w projekcie z wspólnej biblioteki standardowej C++
Z powodu znanego problemu ASan jest niezgodny z obsługą wyjątków w C++, gdy używasz libc++_static
. Ten problem nie występuje podczas korzystania z libc++_shared
.
HWASan ma własną implementację operatorów new
i delete
, których nie można używać, jeśli standardowa biblioteka jest połączona statycznie z projektem.
Aby zmienić to ustawienie, zapoznaj się z sekcją Łączenie z standardową biblioteką C++ tego dokumentu.
Włącz generowanie wskaźnika ramki
HWASan i ASan używają odwijacza opartego na szybko działającym wskaźniku ramki, aby generować informacje o wyświetleniu stosu w przypadku zdarzeń przydzielenia i zwolnienia pamięci. Oznacza to, że aby korzystać z tych funkcji, musisz włączyć generowanie wskaźnika ramki w ustawieniach kompilatora C++. Oznacza to, że musisz wyłączyć optymalizację pomijania wskaźnika ramki.
Aby zmienić to ustawienie, zapoznaj się z sekcją Włączanie generowania wskaźników ramek tego dokumentu.
Konfigurowanie projektu Visual Studio do używania HWASan lub ASan
Włączanie HWASan lub ASan
Aby włączyć HWASan lub ASan, na stronie Ustawienia usługi > Ogólne w sekcji Strony usługi dotyczącej projektu kliknij Właściwości konfiguracji.
Rys. 1. Opcja Właściwości projektu w oknie Eksploratora rozwiązań Visual Studio.
Rysunek 2. Ustawienie Address Sanitizer (ASan) w ogólnych właściwościach projektu.
Aby włączyć HWASan w projekcie, zmień ustawienie Address Sanitizer (ASan) na Hardware ASan Enabled (fsanitize=hwaddress).
Aby włączyć ASan w projekcie, zmień ustawienie Address Sanitizer (ASan) na ASan włączony (fsanitize=address).
Włączanie generowania wskaźnika ramki
Generowanie wskaźnika ramki jest kontrolowane przez ustawienie kompilatora C/C++ Pominij wskaźnik ramki. Można je znaleźć na stronach usługi w sekcji Właściwości konfiguracji > C/C++ > Optymalizacja.
Ilustracja 3: gdzie znaleźć ustawienie Pominij wskaźnik kadru.
Jeśli używasz HWASan lub ASan, ustaw ustawienie Omit Frame Pointer na No (-fno-omit-frame-pointer).
Łączenie standardowej biblioteki C++ w trybie biblioteki udostępnionej
Ustawienie trybu linkera dla standardowej biblioteki C++ znajdziesz na stronie usługi projektu w sekcji Właściwości konfiguracji > Ogólne w sekcji Ustawienia domyślne projektu.
Rysunek 4. Lokalizacja ustawienia trybu linkera dla standardowej biblioteki C++.
Podczas korzystania z HWASan lub ASan ustaw opcję Używanie STL na Użyj standardowych bibliotek C++ (.so). Ta wartość łączy standardową bibliotekę C++ z Twoim projektem jako bibliotekę współdzieloną, co jest wymagane do prawidłowego działania HWASan i ASan.
Tworzenie konfiguracji kompilacji do stosowania narzędzia Address Sanitizer
Jeśli wolisz tymczasowo korzystać z HWASan lub ASan, możesz nie chcieć tworzyć nowej konfiguracji kompilacji tylko na potrzeby tych narzędzi. Może się tak zdarzyć, jeśli projekt jest niewielki, testujesz funkcję lub chcesz rozwiązać problem znaleziony podczas testowania.
Jeśli jednak uznasz, że jest ona przydatna i planujesz regularnie z niej korzystać, możesz utworzyć nową konfigurację kompilacji dla HWASan lub ASan, jak pokazano w przykładzie Teapot. Możesz to zrobić, jeśli na przykład regularnie uruchamiasz narzędzie Address Sanitizer w ramach testów jednostkowych lub podczas całonocnych testów diagnostycznych gry.
Utworzenie osobnej konfiguracji kompilacji może być szczególnie przydatne, jeśli masz duży projekt, który korzysta z dużej liczby różnych bibliotek innych firm, które zwykle łączysz statycznie z biblioteką standardową C++. Specjalne konfiguracje kompilacji mogą pomóc w zapewnieniu, że ustawienia projektu będą zawsze prawidłowe.
Aby utworzyć konfigurację kompilacji, na stronie Właściwości projektu kliknij przycisk Menedżer konfiguracji…, a następnie otwórz menu Konfiguracja aktywnego rozwiązania. Następnie wybierz
Korzystanie z HWASan z niestandardowymi przydzielającymi pamięć
HWASan automatycznie przechwytuje pamięć przydzieloną za pomocą funkcji malloc
(lub new
), aby móc wstrzyknąć tagi do wskaźników i sprawdzić, czy nie ma niezgodności tagów.
Jeśli jednak używasz niestandardowego alokatora pamięci, HWASan nie może automatycznie przechwytywać niestandardowych metod alokacji pamięci. Jeśli chcesz używać HWASan z niestandardowym przydziałem pamięci, zmodyfikuj swój kod, aby wywoływał on HWASan w wyraźny sposób. Wystarczy do tego kilka linii kodu.
Wymagania wstępne
Metody HWASan, do których musisz się odwoływać, są zdefiniowane w tym nagłówku:
#include "sanitizer/hwasan_interface.h"
Przypisz metodę przydziału pamięci do instrumentu
Przydzielaj obiekty z uwzględnieniem dokładności i wyrównania bloku 16-bajtowego. Jeśli na przykład masz przydzielający pulę, który obsługuje obiekty o stałym rozmiarze 24 bajtów, zaokrąglij przydziały do 32 bajtów i wyrównaj je do 16 bajtów.
Wygeneruj tag 8-bitowy. Tag nie może używać wartości 0–16, ponieważ są one zarezerwowane do użytku wewnętrznego.
Aby umożliwić HWASan śledzenie regionu pamięci za pomocą tego tagu:
__hwasan_tag_memory((void*) address, tag, size);
Wstrzyknij tag do 8 najwyższych bitów wskaźnika:
address = __hwasan_tag_pointer((void*) address, tag);
Instrumentowanie metody dealokacji pamięci
Zresetuj tag regionu pamięci, aby spowodować, że kolejne próby dostępu za pomocą dotychczasowych oznaczonych wskaźników się nie powiedzie:
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), 0, size);
Praca z zaalokowanym z wyprzedzeniem zbiorem obiektów
Jeśli alokator pamięci wstępnie przydzieli obiekty w pulach i zamiast ich zwalniać zwraca je z powrotem do puli, metoda zwalniania może bezpośrednio zastąpić tag pamięci i wskaźnik nową wartością:
```
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), tag, size);
ptr = __hwasan_tag_pointer((void*)ptr, tag);
```
Jeśli używasz tej metody, metody alokacji nie muszą oznaczać wskaźników ani bloków pamięci, ale muszą je oznaczać podczas wstępnego przydzielenia obiektów do puli. Przykład użycia tego stylu znajdziesz w plikach PoolAllocator sample.