Das Android-NDK unterstützt Address Sanitizer (auch als ASan bezeichnet) ab API-Level 27 (Android O MR 1).
ASan ist ein schnelles Compiler-basiertes Tool zur Erkennung von Arbeitsspeicherfehlern in nativem Code. ASan erkennt:
- Überlauf/Unterlauf von Stack- und Heap-Zwischenspeicher
- Heap-Nutzung nach der kostenlosen Nutzung
- Stacknutzung außerhalb des Bereichs
- Doppelt kostenlos/wildfrei
Der CPU-Aufwand für ASan ist etwa doppelt so hoch, der Overhead für die Codegröße liegt zwischen 50 und 2x und der Speicheraufwand ist groß (abhängig von Ihren Zuweisungsmustern, aber in der Größenordnung von 2x).
Beispiel-App
Eine Beispiel-App zeigt, wie eine Build-Variante für AS konfiguriert wird.
Eine Community
So erstellen Sie den JNI-Code (nativen Code) Ihrer Anwendung mit Address Sanitizer:
NDK-Build
Führen Sie in Application.mk folgende Schritte aus:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
Für jedes Modul in Android.mk:
LOCAL_ARM_MODE := arm
CMake
Führen Sie im build.gradle-Modul Ihres Moduls folgende Schritte aus:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
Führen Sie für jedes Ziel in Ihrer CMakeLists.txt-Datei folgende Schritte aus:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
Laufen
Ab Android O MR1 (API-Level 27) kann eine Anwendung ein Wrapping-Shell-Script bereitstellen, das den Anwendungsprozess umschließen oder ersetzen kann. Dadurch kann eine debug-fähige Anwendung ihren Anwendungsstart anpassen, was die Verwendung von ASan auf Produktionsgeräten ermöglicht.
- Füge dem Anwendungsmanifest
android:debuggable
hinzu. - Setze
useLegacyPackaging
in der Dateibuild.gradle
deiner App auftrue
. Weitere Informationen finden Sie in der Anleitung zum Umfassen von Shell-Skripts. - Füge die ASan-Laufzeitbibliothek zum
jniLibs
deines App-Moduls hinzu. Fügen Sie jedem Verzeichnis im
src/main/resources/lib
-Verzeichniswrap.sh
-Dateien mit den folgenden Inhalten hinzu.#!/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 "$@"
Wenn das Anwendungsmodul Ihres Projekts den Namen app
hat, sollte die endgültige Verzeichnisstruktur Folgendes enthalten:
<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
Stacktraces
Address Sanitizer muss den Stack bei jedem malloc
/realloc
/free
-Aufruf entladen. Dafür gibt es zwei Optionen:
Ein „schneller“ Framepointer-basierter Entspannungseffekt. Verwenden Sie dazu die Anleitung im Abschnitt „Builds“.
Ein „langsamer“ CFI-Abspann. In diesem Modus verwendet ASan
_Unwind_Backtrace
. Dafür ist nur-funwind-tables
erforderlich, das normalerweise standardmäßig aktiviert ist.
In Malloc/Realloc/free gilt standardmäßig das schnelle Abschalten. Das langsame Entwickeln ist die Standardeinstellung für schwerwiegende Stacktraces. Das langsame Unwinder kann für alle Stacktraces aktiviert werden. Dazu fügen Sie fast_unwind_on_malloc=0
in die Variable ASAN_OPTIONS
in der Datei „wrap.sh“ ein.