Android NDK obsługuje HWAddress Sanitizer, znany też jako HWASan, od wersji NDK r21 i Androida 10 (poziom interfejsu API 29). HWASan jest dostępny tylko na 64-bitowych urządzeniach z architekturą Arm.
HWASan to narzędzie do wykrywania błędów pamięci podobne do ASan. W porównaniu z klasycznym ASan HWASan ma:
- podobny narzut na procesor (~2x),
- podobny narzut na rozmiar kodu (40–50%),
- znacznie mniejszy narzut na pamięć RAM (10–35%).
HWASan wykrywa ten sam zestaw błędów co ASan:
- przepełnienie lub niedopełnienie bufora stosu i sterty,
- użycie sterty po jej zwolnieniu,
- użycie stosu poza zakresem,
- podwójne lub nieprawidłowe zwolnienie.
Dodatkowo HWASan wykrywa też:
- użycie stosu po powrocie.
Przykładowa aplikacja
Przykładowa aplikacja pokazuje, jak skonfigurować wariant kompilacji dla HWASan.
Kompilacja
Aby skompilować kod natywny (JNI) aplikacji za pomocą HWAddress Sanitizer:
ndk-build
W pliku Application.mk:
APP_STL := c++_shared # Or system, or none, but not c++_static.
APP_CFLAGS := -fsanitize=hwaddress -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=hwaddress
CMake (Gradle Groovy)
W pliku build.gradle modułu:
android {
defaultConfig {
externalNativeBuild {
cmake {
# Can also use system or none as ANDROID_STL, but not c++_static.
arguments "-DANDROID_STL=c++_shared"
}
}
}
}
W przypadku każdego celu w pliku CMakeLists.txt:
target_compile_options(${TARGET} PUBLIC -fsanitize=hwaddress -fno-omit-frame-pointer)
target_link_options(${TARGET} PUBLIC -fsanitize=hwaddress)
W NDK 27 lub nowszym możesz też użyć tego kodu w pliku build.gradle i nie musisz zmieniać pliku CMakeLists.txt:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DANDROID_SANITIZE=hwaddress"
}
}
}
}
Nie będzie to działać, jeśli używasz ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false.
CMake (Gradle Kotlin)
W pliku build.gradle modułu:
android {
defaultConfig {
externalNativeBuild {
cmake {
# Can also use system or none as ANDROID_STL, but not c++_static.
arguments += "-DANDROID_STL=c++_shared"
}
}
}
}
W przypadku każdego celu w pliku CMakeLists.txt:
target_compile_options(${TARGET} PUBLIC -fsanitize=hwaddress -fno-omit-frame-pointer)
target_link_options(${TARGET} PUBLIC -fsanitize=hwaddress)
W NDK 27 lub nowszym możesz też użyć tego kodu w pliku build.gradle i nie musisz zmieniać pliku CMakeLists.txt:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments += "-DANDROID_SANITIZE=hwaddress"
}
}
}
}
Nie będzie to działać, jeśli używasz ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false.
Android 14 lub nowszy: dodaj wrap.sh
Jeśli używasz Androida 14 lub nowszego, możesz użyć skryptu wrap.sh, aby uruchomić aplikację z możliwością debugowania na dowolnym urządzeniu z Androidem. Jeśli wykonasz czynności opisane w instrukcjach konfiguracji , możesz pominąć ten krok.
Postępuj zgodnie z instrukcjami, aby
spakować skrypt wrap.sh i dodać
ten skrypt wrap.sh dla arm64-v8a.
#!/system/bin/sh
LD_HWASAN=1 exec "$@"
Uruchom
Jeśli używasz Androida w wersji starszej niż 14 lub nie dodasz skryptu wrap.sh , przed uruchomieniem aplikacji postępuj zgodnie z instrukcjami konfiguracji.
Uruchom aplikację jak zwykle. Gdy zostanie wykryty błąd pamięci, aplikacja ulegnie awarii z SIGABRT i wyświetli szczegółowy komunikat w logcat. Kopia wiadomości znajduje się w pliku w katalogu /data/tombstones i wygląda 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)
Po komunikacie mogą pojawić się dodatkowe informacje na potrzeby debugowania, w tym lista aktywnych wątków w aplikacji, tagi pobliskich alokacji pamięci i wartości rejestrów procesora.
Więcej informacji o komunikatach o błędach HWASan znajdziesz w artykule Informacje o raportach HWASan.
Kompilowanie plików wykonywalnych w wierszu poleceń
Na Androidzie 14 i nowszym możesz kompilować i uruchamiać pliki wykonywalne instrumentowane za pomocą HWASan. W przypadku plików wykonywalnych możesz użyć tej samej konfiguracji, która jest opisana w sekcji Kompilacja w przypadku ndk-build lub CMake. Prześlij pliki wykonywalne na urządzenie z Androidem 14 lub nowszym i uruchom je jak zwykle za pomocą powłoki.
Jeśli używasz libc++, upewnij się, że używasz współdzielonej biblioteki STL, prześlij ją na urządzenie i ustaw LD_LIBRARY_PATH na katalog, w którym się znajduje, podczas uruchamiania pliku binarnego.
Jeśli nie używasz Gradle, zapoznaj się z dokumentacją NDK, aby dowiedzieć się, jak kompilować z wiersza poleceń za pomocą CMake i ndk-build.
Android 13 lub starszy: konfiguracja
Jeśli Twoje urządzenie ma Androida 14 lub nowszego, możesz pominąć ten krok i postępować zgodnie z instrukcjami dotyczącymi używania wrap.sh w sekcji Kompilacja. Możesz też postępować zgodnie z instrukcjami w tej sekcji i pominąć instrukcje dotyczące używania wrap.sh.
W przypadku Androida w wersji starszej niż 14 aplikacje HWASan wymagają do działania kompilacji Androida z HWASan. Na obsługiwanych urządzeniach Pixel możesz wgrać wstępnie skompilowane obrazy HWASan. Kompilacje są dostępne na ci.android.com. Możesz tam kliknąć kwadrat odpowiadający kompilacji, którą chcesz pobrać, aby uzyskać link Flash Build. Wymaga to znajomości kryptonimu telefonu.
Łatwiej może być przejść bezpośrednio do flash.android.com, ponieważ tam proces rozpoczyna się od wykrycia urządzenia i wyświetla tylko kompilacje, których możesz użyć. Poniższe obrazy ilustrują proces konfiguracji w tym narzędziu.
Włącz na urządzeniu tryb programisty i podłącz je do komputera za pomocą kabla USB. Kliknij Add new device (Dodaj nowe urządzenie), wybierz urządzenie w oknie i kliknij Connect (Połącz).
Gdy urządzenie zostanie połączone, kliknij je, aby skonfigurować kompilację.
W polu Select a build ID (Wybierz identyfikator kompilacji) wybierz gałąź aosp-master-with-phones-throttled, aby automatycznie wybrać prawidłowy obraz dla podłączonego urządzenia.
Aby flashować urządzenie, kliknij Install (Zainstaluj).
Więcej informacji o wymaganej konfiguracji znajdziesz w dokumentacji Android Flash Tool. Możesz też zapoznać się z dokumentacją AOSP, aby dowiedzieć się, jak skompilować obraz HWASan z kodu źródłowego.