Android NDK mendukung Address Sanitizer (juga dikenal sebagai ASan) mulai dari API level 27 (Android O MR 1).
ASan adalah alat cepat berbasis compiler untuk mendeteksi bug memori dalam kode native. ASan dapat mendeteksi:
- Stack dan luapan/underflow buffer heap
- Penggunaan heap setelah tersedia
- Penggunaan stack di luar cakupan
- Double free/wild free
ASan dapat dijalankan pada ARM 32 bit dan 64 bit, serta x86 dan x86-64. Overhead CPU ASan kurang lebih 2x, overhead ukuran kodenya antara 50% hingga 2x, dan overhead memorinya besar (bergantung pada pola alokasi, tetapi kurang lebih 2x).
Untuk ARM 64-bit, HWAddress Sanitizer sangat disarankan.
Aplikasi Contoh
Aplikasi contoh menunjukkan cara mengonfigurasi varian build untuk asan.
Build
Untuk membuat kode native (JNI) aplikasi dengan Address Sanitizer, lakukan hal berikut:
ndk-build
Dalam Application.mk Anda:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
Untuk setiap modul dalam Android.mk:
LOCAL_ARM_MODE := arm
CMake
Dalam build.gradle modul Anda:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
Untuk setiap target dalam CMakeLists.txt:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
Run
Mulai dari Android O MR1 (API level 27), aplikasi dapat menyediakan skrip shell wrap yang dapat menggabungkan atau mengganti proses aplikasi. Hal ini memungkinkan aplikasi yang dapat di-debug menyesuaikan proses memulai aplikasinya, sehingga memungkinkan penggunaan ASan di perangkat produksi.
- Tambahkan
android:debuggable
ke manifes aplikasi. - Tetapkan
useLegacyPackaging
ketrue
dalam filebuild.gradle
aplikasi Anda. Lihat panduan skrip shell wrap untuk informasi selengkapnya. - Tambahkan library runtime ASan ke
jniLibs
modul aplikasi. Tambahkan file
wrap.sh
dengan konten berikut ini ke setiap direktori di direktorisrc/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 "$@"
Dengan asumsi bahwa modul aplikasi project diberi nama app
, struktur direktori akhir
Anda harus menyertakan hal berikut:
<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
Pelacakan tumpukan
Address Sanitizer perlu melepaskan stack pada setiap panggilan
malloc
/realloc
/free
. Ada dua opsi di sini:
Unwinder berbasis pointer frame yang "cepat". Unwinder inilah yang perlu Anda gunakan jika mengikuti petunjuk di bagian membuat.
Unwinder CFI yang "lambat". Dalam mode ini, ASan menggunakan
_Unwind_Backtrace
. Unwinder ini hanya memerlukan-funwind-tables
, yang biasanya diaktifkan secara default.
Unwinder cepat merupakan default untuk malloc/realloc/free. Unwinder lambat adalah
default untuk pelacakan tumpukan fatal. Unwinder lambat dapat diaktifkan untuk semua
pelacakan tumpukan dengan menambahkan fast_unwind_on_malloc=0
ke variabel ASAN_OPTIONS
dalam wrap.sh.