Android NDK, API düzeyi 27'den (Android O MR 1) itibaren Address Sanitizer'ı (ASan olarak da bilinir) destekler.
ASan, yerel kodda bellek hatalarını tespit etmek için kullanılan, derleyici tabanlı hızlı bir araçtır. ASan'ın algıladığı sorunlar:
- Yığın ve bellek yığını arabellek taşması/taşma altı
- Serbest bırakıldıktan sonra yığın kullanımı
- Yığın kullanımı kapsam dışında
- İki katı ücretsiz/wild ücretsiz
ASan'ın CPU ek yükü yaklaşık 2 kat, kod boyutu ek yükü% 50 ile 2 kat arasında ve bellek ek yükü büyüktür (ayırma kalıplarınıza bağlıdır ancak 2 kat civarındadır).
Sample App
Örnek bir uygulamada, asan için derleme değişkeninin nasıl yapılandırılacağı gösterilmektedir.
Derleme
Uygulamanızın yerel (JNI) kodunu Address Sanitizer ile oluşturmak için aşağıdakileri yapın:
ndk-build
Application.mk dosyanızda:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
Android.mk dosyanızdaki her modül için:
LOCAL_ARM_MODE := arm
CMake
Modülünüzün build.gradle dosyasında:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
CMakeLists.txt dosyanızdaki her hedef için:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
Çalıştır
Android O MR1 (API düzeyi 27) sürümünden itibaren uygulamalar, uygulama sürecini sarmalayabilen veya değiştirebilen bir sarmalama kabuk komut dosyası sağlayabilir. Bu, hata ayıklanabilir bir uygulamanın uygulama başlangıcını özelleştirmesine olanak tanır. Bu sayede, üretim cihazlarında ASan kullanılabilir.
- Uygulama manifestine
android:debuggableekleyin. - Uygulamanızın
build.gradledosyasındauseLegacyPackagingdeğerinitrueolarak ayarlayın. Daha fazla bilgi için wrap kabuk komut dosyası kılavuzuna bakın. - ASan çalışma zamanı kitaplığını uygulama modülünüzün
jniLibsbölümüne ekleyin. wrap.shdizininizdeki her dizine aşağıdaki içeriklere sahipwrap.shdosyaları ekleyin.src/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 "$@"
Projenizin uygulama modülünün app olarak adlandırıldığını varsayarsak nihai dizin yapınız şunları içermelidir:
<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
Yığın izleri
Address Sanitizer'ın her malloc/realloc/free çağrısında yığını geri sarması gerekir. Bu durumda iki seçeneğiniz vardır:
"Hızlı" bir çerçeve işaretçisi tabanlı geri sarıcı. Bu, yapı bölümündeki talimatlar uygulandığında kullanılan öğedir.
"Yavaş" bir CFI çözücü. Bu modda ASan,
_Unwind_Backtracekullanır. Bu özellik için yalnızca-funwind-tablesgerekir. Bu özellik normalde varsayılan olarak etkindir.
Hızlı sarmalayıcı, malloc/realloc/free için varsayılandır. Yavaş çözücü, önemli yığın izlemeleri için varsayılandır. wrap.sh dosyanızdaki ASAN_OPTIONS değişkenine fast_unwind_on_malloc=0 ekleyerek yavaş sarmayı tüm yığın izleri için etkinleştirebilirsiniz.