HWAddress-Sanitizer

Das Android NDK unterstützt HWAddress Sanitizer (HWASan) ab NDK r21 und Android 10 (API-Level 29). HWASan ist nur auf 64‑Bit-Arm-Geräten verfügbar.

HWASan ist ein Tool zur Erkennung von Arbeitsspeicherfehlern, das ASan ähnelt. Im Vergleich zu klassischem ASan bietet HWASan:

  • Ähnlicher CPU-Overhead (~2x)
  • Ähnlicher Mehraufwand für die Codegröße (40–50%)
  • Viel geringerer RAM-Overhead (10–35 %)

HWASan erkennt dieselben Fehler wie ASan:

  • Stack- und Heap-Pufferüberlauf oder -unterlauf
  • Heap-Nutzung nach dem Freigeben
  • Stack-Nutzung außerhalb des Anwendungsbereichs
  • Doppelt kostenlos oder wild kostenlos

Außerdem erkennt HWASan Folgendes:

  • Stapel nach Rückgabe verwenden

Beispiel-App

Eine Beispiel-App zeigt, wie eine Build-Variante für hwasan konfiguriert wird.

Entwickeln

So erstellen Sie den nativen (JNI-)Code Ihrer App mit HWAddress Sanitizer:

ndk-build

In Ihrer Application.mk-Datei:

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)

In der build.gradle-Datei Ihres Moduls:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                # Can also use system or none as ANDROID_STL, but not c++_static.
                arguments "-DANDROID_STL=c++_shared"
            }
        }
    }
}

Für jedes Ziel in Ihrer CMakeLists.txt-Datei:

target_compile_options(${TARGET} PUBLIC -fsanitize=hwaddress -fno-omit-frame-pointer)
target_link_options(${TARGET} PUBLIC -fsanitize=hwaddress)

Mit NDK 27 oder höher können Sie auch Folgendes in Ihrem build.gradle verwenden und müssen CMakeLists.txt nicht ändern:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                arguments "-DANDROID_SANITIZE=hwaddress"
            }
        }
    }
}

Das funktioniert nicht, wenn Sie ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false verwenden.

CMake (Gradle Kotlin)

In der build.gradle-Datei Ihres Moduls:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                # Can also use system or none as ANDROID_STL, but not c++_static.
                arguments += "-DANDROID_STL=c++_shared"
            }
        }
    }
}

Für jedes Ziel in Ihrer CMakeLists.txt-Datei:

target_compile_options(${TARGET} PUBLIC -fsanitize=hwaddress -fno-omit-frame-pointer)
target_link_options(${TARGET} PUBLIC -fsanitize=hwaddress)

Mit NDK 27 oder höher können Sie auch Folgendes in Ihrem build.gradle verwenden und müssen CMakeLists.txt nicht ändern:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                arguments += "-DANDROID_SANITIZE=hwaddress"
            }
        }
    }
}

Das funktioniert nicht, wenn Sie ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false verwenden.

Android 14 oder höher: wrap.sh hinzufügen

Wenn Sie Android 14 oder höher verwenden, können Sie ein wrap.sh-Script verwenden, um Ihre debuggable App auf einem beliebigen Android-Gerät auszuführen. Sie können diesen Schritt überspringen, wenn Sie die Schritte in der Einrichtungsanleitung ausgeführt haben.

Folgen Sie der Anleitung zum Verpacken eines wrap.sh-Skripts, um das folgende wrap.sh-Skript für arm64-v8a hinzuzufügen.

#!/system/bin/sh
LD_HWASAN=1 exec "$@"

Laufen

Wenn Sie eine Android-Version vor Version 14 verwenden oder kein „wrap.sh“-Script hinzugefügt haben, folgen Sie der Einrichtungsanleitung, bevor Sie Ihre App ausführen.

Führen Sie die App wie gewohnt aus. Wenn ein Arbeitsspeicherfehler erkannt wird, stürzt eine App mit SIGABRT ab und gibt eine detaillierte Meldung in logcat aus. Eine Kopie der Nachricht finden Sie in einer Datei unter /data/tombstones. Sie sieht so aus:

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)

Auf die Meldung können zusätzliche Debugging-Informationen folgen, darunter die Liste der aktiven Threads in der Anwendung, Tags von Arbeitsspeicherzuweisungen in der Nähe und CPU-Registerwerte.

Weitere Informationen zu HWASan-Fehlermeldungen finden Sie unter HWASan-Berichte.

Befehlszeilen-Executables erstellen

Sie können ausführbare Dateien, die mit HWASan instrumentiert wurden, unter Android 14 und höher erstellen und ausführen. Sie können dieselbe Konfiguration wie in Build für ndk-build oder CMake für Ihre ausführbaren Dateien verwenden. Übertragen Sie die ausführbaren Dateien auf ein Gerät mit Android 14 oder höher und führen Sie sie wie gewohnt über die Shell aus.

Wenn Sie libc++ verwenden, müssen Sie die freigegebene STL verwenden, sie auf das Gerät übertragen und LD_LIBRARY_PATH auf das Verzeichnis setzen, das sie enthält, wenn Sie das Binärprogramm ausführen.

Wenn Sie Gradle nicht verwenden, finden Sie in der NDK-Dokumentation Informationen zum Erstellen über die Befehlszeile mit CMake und ndk-build.

Android 13 oder niedriger: Einrichtung

Wenn auf Ihrem Gerät Android 14 oder höher ausgeführt wird, können Sie diesen Schritt überspringen und der Anleitung zur Verwendung von wrap.sh im Abschnitt Build folgen. Sie können auch diesen Abschnitt lesen und die Anleitung zur Verwendung von wrap.sh überspringen.

Vor Android 14 benötigten HWASan-Anwendungen einen HWASan-Build von Android, um ausgeführt zu werden. Sie können vorgefertigte HWASan-Images auf unterstützte Pixel-Geräte flashen. Die Builds sind auf ci.android.com verfügbar. Dort können Sie auf das Quadrat für den gewünschten Build klicken, um einen Flash Build-Link zu erhalten. Dazu müssen Sie den Codenamen Ihres Smartphones kennen.

Geräte-Build flashen

Es ist möglicherweise einfacher, direkt zu flash.android.com zu gehen, da der Ablauf dort mit der Erkennung Ihres Geräts beginnt und nur Builds angezeigt werden, die Sie verwenden können. Die folgenden Bilder veranschaulichen den Einrichtungsablauf in diesem Tool.

Aktivieren Sie den Entwicklermodus auf Ihrem Gerät und verbinden Sie es über ein USB-Kabel mit Ihrem Computer. Klicken Sie auf Neues Gerät hinzufügen, wählen Sie Ihr Gerät im Dialogfeld aus und klicken Sie auf Verbinden.

Gerät zum Blinken erkennen Gerät auswählen, mit dem eine Verbindung hergestellt werden soll

Klicken Sie nach dem Herstellen der Verbindung auf das Gerät, um den Build zu konfigurieren. Wählen Sie im Feld Build-ID auswählen den aosp-master-with-phones-throttled-Zweig aus, um automatisch das richtige Image für das verbundene Gerät auszuwählen.

Gerät zum Flashen auswählen Flash-Optionen bestätigen und Gerät flashen

Klicken Sie auf Installieren, um das Gerät zu flashen.

Weitere Informationen zur erforderlichen Einrichtung finden Sie in der Dokumentation zum Android Flash Tool. Alternativ können Sie in der AOSP-Dokumentation nachlesen, wie Sie ein HWASan-Image aus dem Quellcode erstellen.