Android NDK mendukung Address Sanitizer (juga dikenal sebagai ASan) mulai dari level API 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
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).
Aplikasi Contoh
Aplikasi contoh menunjukkan cara mengonfigurasi varian build untuk ASan.
Build
Untuk membangun 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.