Pakiet Android NDK na Androida obsługuje usługę Address Sanitizer (inaczej ASan) na początku z interfejsem API poziomu 27 (Android O MR 1).
ASan to szybkie narzędzie oparte na kompilatorze do wykrywania błędów pamięci w kodzie natywnym. ASan wykrywa:
- Przepełnienie/niedopełnienie bufora stosu i sterty
- Wykorzystanie sterty po bezpłatnym
- Użycie stosu poza zakresem
- Podwójny wolny/szlachetny
Narzut procesora ASan jest około 2-krotnie większy, rozmiar kodu od 50% do 2-krotnie, i zużycie pamięci jest duże (zależnie od wzorców alokacji, ale w kolejności 2x).
Przykładowa aplikacja
Przykładowa aplikacja pokazuje, jak skonfigurować wariant kompilacji dla pliku Asan.
Budowanie
Aby utworzyć natywny kod aplikacji (JNI) za pomocą narzędzia Address Sanitizer, wykonaj :
ndk-build
W pliku Application.mk:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
W przypadku każdego modułu w pliku Android.mk:
LOCAL_ARM_MODE := arm
CMake
W pliku build.gradle modułu:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
W przypadku każdego elementu docelowego w pliku CMakeLists.txt:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
Uruchom
Począwszy od Androida O MR1 (poziom interfejsu API 27) aplikacja może udostępniać skrypt powłoki, który może opakować lub zastąpić proces aplikacji. Dzięki temu aplikacji z możliwością debugowania, aby dostosować uruchamianie aplikacji, i używania ASan na urządzeniach produkcyjnych.
- Dodaj
android:debuggable
do pliku manifestu aplikacji. - Ustaw
useLegacyPackaging
dotrue
w plikubuild.gradle
aplikacji. Zapoznaj się z przewodnikiem po zawijaniu skryptu powłoki . - Dodaj bibliotekę środowiska wykonawczego ASan do sekcji
jniLibs
modułu aplikacji. Dodaj pliki
wrap.sh
o podanej zawartości do każdego katalogu w swoim katalogusrc/main/resources/lib
.#!/system/bin/sh HERE="$(cd "$(dirname "$0")" && pwd)" export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1 ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so) if [ -f "$HERE/libc++_shared.so" ]; then # Workaround for https://github.com/android-ndk/ndk/issues/988. export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so" else export LD_PRELOAD="$ASAN_LIB" fi "$@"
Zakładając, że moduł aplikacji Twojego projektu nazywa się app
,
powinna zawierać:
<project root>
└── app
└── src
└── main
├── jniLibs
│ ├── arm64-v8a
│ │ └── libclang_rt.asan-aarch64-android.so
│ ├── armeabi-v7a
│ │ └── libclang_rt.asan-arm-android.so
│ ├── x86
│ │ └── libclang_rt.asan-i686-android.so
│ └── x86_64
│ └── libclang_rt.asan-x86_64-android.so
└── resources
└── lib
├── arm64-v8a
│ └── wrap.sh
├── armeabi-v7a
│ └── wrap.sh
├── x86
│ └── wrap.sh
└── x86_64
└── wrap.sh
Śledzenie stosu
Usługa Address Sanitizer musi rozwijać stos co malloc
/realloc
/free
. Dostępne są 2 opcje:
Szybkość elementu rozwijania opartego na wskaźniku ramki. Jest to metoda stosowana przez w sekcji dotyczącej budynków.
„Wolno” Narzędzie do rozwijania interfejsu CFI. W tym trybie ASan używa parametru
_Unwind_Backtrace
. it wymaga tylko funkcji-funwind-tables
, która jest normalnie włączona domyślnie.
Szybkie rozwijanie jest domyślnym ustawieniem dla Malloc/realloc/free. Wolne przewijanie to
domyślna dla krytycznych zrzutów stosu. Wolne rozwijanie można włączyć dla wszystkich
zrzuty stosu, dodając fast_unwind_on_malloc=0
do zmiennej ASAN_OPTIONS
w Twoim pliku wrap.sh.