Igienizzante per indirizzi HW

L'NDK Android supporta HWAddress Sanitizer, noto anche come HWASan, a partire da NDK r21 e Android 10 (livello API 29). HWASan è disponibile solo su dispositivi Arm a 64 bit.

HWASan è uno strumento di rilevamento degli errori di memoria simile ad ASan. Rispetto ad ASan classico, HWASan ha:

  • Overhead della CPU simile (~2x)
  • Overhead delle dimensioni del codice simile (40-50%)
  • Overhead della RAM molto inferiore (10-35%)

HWASan rileva lo stesso insieme di bug di ASan:

  • Overflow o underflow del buffer dello stack e dell'heap
  • Heap use-after-free
  • Utilizzo dello stack al di fuori dell'ambito
  • Doppio free o wild free

Inoltre, HWASan rileva anche:

  • Utilizzo dello stack dopo il reso

App di esempio

Un'app di esempio mostra come configurare una variante di build per hwasan.

Crea

Per creare il codice nativo (JNI) della tua app con HWAddress Sanitizer, segui questi passaggi:

ndk-build

Nel file Application.mk:

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)

Nel file build.gradle del modulo:

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

Per ogni target in CMakeLists.txt:

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

Con NDK 27 o versioni successive, puoi anche utilizzare quanto segue in build.gradle e non devi modificare CMakeLists.txt:

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

Questa operazione non funziona quando utilizzi ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false.

CMake (Gradle Kotlin)

Nel file build.gradle del modulo:

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

Per ogni target in CMakeLists.txt:

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

Con NDK 27 o versioni successive, puoi anche utilizzare quanto segue in build.gradle e non devi modificare CMakeLists.txt:

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

Questa operazione non funziona quando utilizzi ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false.

Android 14 o versioni successive: aggiungi wrap.sh

Se utilizzi Android 14 o versioni successive, puoi utilizzare uno script wrap.sh per eseguire la tua app debuggable su qualsiasi dispositivo Android. Puoi saltare questo passaggio se hai scelto di seguire i passaggi nelle istruzioni di configurazione.

Segui le istruzioni per creare un pacchetto di uno script wrap.sh per aggiungere il seguente script wrap.sh per arm64-v8a.

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

Esegui

Se utilizzi una versione di Android precedente alla 14 o non hai aggiunto uno script wrap.sh, segui le istruzioni di configurazione prima di eseguire l'app.

Esegui l'app come al solito. Quando viene rilevato un errore di memoria, un'app si arresta in modo anomalo con SIGABRT e stampa un messaggio dettagliato in logcat. Una copia del messaggio è disponibile in un file in /data/tombstones e ha questo aspetto:

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)

Il messaggio può essere seguito da informazioni di debug aggiuntive, tra cui l'elenco dei thread attivi nell'applicazione, i tag delle allocazioni di memoria vicine e i valori dei registri della CPU.

Per ulteriori informazioni sui messaggi di errore di HWASan, consulta la sezione Informazioni sui report HWASan.

Creazione di eseguibili della riga di comando

Puoi creare ed eseguire eseguibili strumentati con HWASan su Android 14 e versioni successive. Puoi utilizzare la stessa configurazione descritta in Build per ndk-build o CMake per i tuoi eseguibili. Trasferisci gli eseguibili su un dispositivo con Android 14 o versioni successive ed eseguili normalmente utilizzando la shell.

Se utilizzi libc++, assicurati di utilizzare la STL condivisa, trasferiscila al dispositivo e imposta LD_LIBRARY_PATH sulla directory che la contiene quando esegui il binario.

Se non utilizzi Gradle, consulta la documentazione NDK per scoprire come eseguire la build dalla riga di comando con CMake e ndk-build.

Android 13 o versioni precedenti: configurazione

Se sul dispositivo è installato Android 14 o versioni successive, puoi saltare questo passaggio e seguire le istruzioni per l'utilizzo di wrap.sh nella sezione Build. Puoi anche scegliere di seguire questa sezione e saltare le istruzioni per l'utilizzo di wrap.sh.

Prima di Android 14, le applicazioni HWASan richiedono una build HWASan di Android per essere eseguite. Puoi eseguire il flashing di immagini HWASan precompilate sui dispositivi Pixel supportati. Le build sono disponibili su ci.android.com, dove puoi fare clic sul quadrato della build esatta per ottenere un link Flash Build. Per farlo, devi conoscere il nome in codice del tuo smartphone.

Installare una build del dispositivo

Potrebbe essere più semplice andare direttamente su flash.android.com perché il flusso inizia con il rilevamento del dispositivo e mostra solo le build che puoi utilizzare. Le immagini seguenti illustrano il flusso di configurazione in questo strumento.

Attiva la modalità sviluppatore sul dispositivo e collegalo al computer utilizzando un cavo USB. Fai clic su Aggiungi nuovo dispositivo, seleziona il tuo dispositivo dalla finestra di dialogo e fai clic su Connetti.

Rilevare un dispositivo da aggiornare Seleziona il dispositivo a cui connetterti.

Dopo aver collegato il dispositivo, fai clic per configurare la build. Nella casella Seleziona un ID build, seleziona il ramo aosp-master-with-phones-throttled per scegliere automaticamente l'immagine corretta per il dispositivo che hai collegato.

Seleziona il dispositivo da aggiornare Conferma le opzioni di flash e esegui il flash del dispositivo

Fai clic su Installa per eseguire il flash del dispositivo.

Per maggiori dettagli sulla configurazione necessaria, consulta la documentazione di Android Flash Tool. In alternativa, puoi consultare la documentazione AOSP per istruzioni sulla creazione di un'immagine HWASan dal codice sorgente.