Das Android NDK unterstützt ab sofort Address Sanitizer (auch bekannt als ASan) mit API-Level 27 (Android O MR 1).
ASan ist ein schnelles Compiler-basiertes Tool zur Erkennung von Speicherfehlern in nativem Code. ASan erkennt:
- Überlauf/Unterlauf für Stack- und Heap-Zwischenspeicher
- Heap-Nutzung nach kostenloser Nutzung
- Stack-Verwendung außerhalb des Zuständigkeitsbereichs
- Doppeltes Freibad/Wildtreffer
Der CPU-Overhead von ASan beträgt ungefähr das Doppelte, der Codegrößen-Overhead liegt zwischen 50 und 2x. und der Arbeitsspeicher-Overhead hoch ist (abhängig von Ihren Zuweisungsmustern, in der Reihenfolge 2x).
Beispiel-App
Beispiel-App zeigt, wie eine Build-Variante für asan konfiguriert wird.
Eine Community
Um den nativen JNI-Code Ihrer App mit Address Sanitizer zu erstellen, führen Sie die Folgendes:
NK-Build
Gehen Sie in der Datei Application.mk so vor:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
Gehen Sie für jedes Modul in Ihrer Android.mk-Datei so vor:
LOCAL_ARM_MODE := arm
CMake
Gehen Sie in der build.gradle-Datei Ihres Moduls so vor:
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 der Datei CMakeLists.txt 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 App shell-Skript, das den Anwendungsprozess umschließen oder ersetzen kann. Dadurch können Sie eine Debug-fähige Anwendung, mit der der Start der Anwendung angepasst werden kann, und ASan auf Produktionsgeräten nutzen.
- Füge dem App-Manifest
android:debuggable
hinzu. - Festlegen
useLegacyPackaging
in derbuild.gradle
-Datei deiner App auftrue
. Siehe die Anleitung zum Wrapping Shell-Skript. . - Füge die ASan-Laufzeitbibliothek zum
jniLibs
deines App-Moduls hinzu. Fügen Sie jedem Verzeichnis in Ihrem Verzeichnis
wrap.sh
-Dateien mit folgendem Inhalt hinzu:src/main/resources/lib
-Verzeichnis.#!/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 "$@"
Angenommen, das Anwendungsmodul Ihres Projekts heißt app
, Ihr endgültiges Verzeichnis
sollte 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 Stapel an jedem malloc
/realloc
/free
loslösen.
anrufen. Dafür gibt es zwei Optionen:
Ein „schnelles“ auf Frame-Pointer-Tools. Dies wird verwendet, wenn Sie die im Abschnitt "Gebäude".
Ein „langsames“ CFI-Abwickler. In diesem Modus verwendet ASan
_Unwind_Backtrace
. Es erfordert nur-funwind-tables
, das normalerweise standardmäßig aktiviert ist.
Der schnelle Abwickler ist die Standardeinstellung für „maloc/realloc/free“. Der langsame Abwechslung
Standard für schwerwiegende Stacktraces. Der langsame Entspannungsmodus kann für alle aktiviert werden
Stacktraces hinzufügen, indem Sie fast_unwind_on_malloc=0
in die Variable ASAN_OPTIONS
einfügen
in wrap.sh.