L'NDK di Android supporta Address Sanitizer (noto anche come ASan) a partire dal livello API 27 (Android O MR 1).
ASan è uno strumento rapido basato su compilatore per rilevare i bug di memoria nel codice nativo. ASan rileva:
- Overflow/underflow dello stack e del buffer heap
- Utilizzo heap dopo la disponibilità
- Utilizzo dello stack al di fuori dell'ambito
- Doppio free/wild free
L'overhead della CPU di ASan è circa il doppio, l'overhead delle dimensioni del codice è compreso tra il 50% e il doppio e l'overhead della memoria è elevato (dipende dai pattern di allocazione, ma dell'ordine di 2 volte).
App di esempio
Un'app di esempio mostra come configurare una variante della build per asan.
Crea
Per creare il codice nativo dell'app (JNI) con Address Sanitizer:
build-ndk
Nel file Application.mk:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
Per ogni modulo nel tuo file Android.mk:
LOCAL_ARM_MODE := arm
Marca
Nel file build.gradle del modulo:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
Per ogni target nel file CMakeLists.txt:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
Corsa
A partire da Android O MR1 (livello API 27), un'applicazione può fornire uno script shell di wrapping che può eseguire il wrapping o sostituire il processo dell'applicazione. Ciò consente a un'applicazione di cui è possibile eseguire il debug di personalizzare l'avvio dell'applicazione, il che consente l'utilizzo di ASan sui dispositivi di produzione.
- Aggiungi
android:debuggable
al manifest dell'applicazione. - Imposta
useLegacyPackaging
sutrue
nel filebuild.gradle
della tua app. Per ulteriori informazioni, consulta la guida relativa allo script shell di wrapping. - Aggiungi la libreria di runtime ASan al
jniLibs
del modulo dell'app. Aggiungi file
wrap.sh
con i seguenti contenuti a ogni directory nella directorysrc/main/resources/lib
.#!/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 "$@"
Supponendo che il modulo dell'applicazione del progetto sia denominato app
, la struttura della directory finale dovrebbe includere quanto segue:
<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
Analisi dello stack
Address Sanitizer deve sbloccare lo stack a ogni chiamata malloc
/realloc
/free
. Le opzioni disponibili sono due:
Uno svolgimento "veloce" basato sul puntatore a frame. Questa è la sezione che viene utilizzata seguendo le istruzioni nella sezione sugli edifici.
Una "lenta" sessione di relax della CFI. In questa modalità, ASan utilizza
_Unwind_Backtrace
. Richiede solo-funwind-tables
, che in genere è abilitato per impostazione predefinita.
Per Malloc/realloc/free viene impostato lo sblocco rapido. Lo sviluppatore lento è l'impostazione predefinita per le analisi dello stack irreversibili. Lo svolgitore lento può essere abilitato per tutte
le analisi dello stack aggiungendo fast_unwind_on_malloc=0
alla variabile ASAN_OPTIONS
nel tuo wrap.sh.