Adressdesinfektionsmittel

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.

  1. Füge dem App-Manifest android:debuggable hinzu.
  2. Festlegen useLegacyPackaging in der build.gradle-Datei deiner App auf true. Siehe die Anleitung zum Wrapping Shell-Skript. .
  3. Füge die ASan-Laufzeitbibliothek zum jniLibs deines App-Moduls hinzu.
  4. 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:

  1. Ein „schnelles“ auf Frame-Pointer-Tools. Dies wird verwendet, wenn Sie die im Abschnitt "Gebäude".

  2. 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.