اندروید NDK از Address Sanitizer (که با نام ASan نیز شناخته میشود) با API سطح ۲۷ (اندروید O نسخه ۱) پشتیبانی میکند.
ASan ابزاری سریع مبتنی بر کامپایلر برای تشخیص اشکالات حافظه در کد بومی است. ASan موارد زیر را تشخیص میدهد:
- سرریز/کمریز بافر پشته و هیپ
- استفاده از هیپ پس از آزادسازی
- استفاده از پشته در خارج از محدوده
- دو برابر رایگان/وحشی رایگان
سربار CPU در ASan تقریباً ۲ برابر، سربار اندازه کد بین ۵۰٪ تا ۲ برابر و سربار حافظه زیاد است (بسته به الگوهای تخصیص شما، اما از مرتبه ۲ برابر).
نمونه برنامه
A sample app shows how to configure a build variant for asan.
ساختن
برای ساخت کد بومی (JNI) برنامه خود با Address Sanitizer ، موارد زیر را انجام دهید:
ساخت ndk
در Application.mk خود:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
برای هر ماژول در Android.mk شما:
LOCAL_ARM_MODE := arm
سیمیک
در فایل build.gradle ماژول خود:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
برای هر هدف در CMakeLists.txt خود:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
اجرا کنید
با شروع Android O MR1 (سطح API 27)، یک برنامه میتواند یک اسکریپت پوسته پوششی ارائه دهد که میتواند فرآیند برنامه را پوشش داده یا جایگزین کند. این به یک برنامه قابل اشکالزدایی اجازه میدهد تا راهاندازی برنامه خود را سفارشی کند، که امکان استفاده از ASan را در دستگاههای تولیدی فراهم میکند.
- Add
android:debuggableto the application manifest. - Set
useLegacyPackagingtotruein your app'sbuild.gradlefile. See the wrap shell script guide for more information. - کتابخانه زمان اجرای ASan را به
jniLibsماژول برنامه خود اضافه کنید. فایلهای
wrap.shبا محتوای زیر را به هر دایرکتوری در دایرکتوری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 "$@"
Assuming your project's application module is named app , your final directory structure should include the following:
<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
ردیابی پشته
Address Sanitizer needs to unwind the stack on every malloc / realloc / free call. There are two options here:
یک بازکننده سریع مبتنی بر اشارهگر فریم. این چیزی است که با دنبال کردن دستورالعملهای بخش ساخت ، استفاده میشود.
A "slow" CFI unwinder. In this mode ASan uses
_Unwind_Backtrace. It requires only-funwind-tables, which is normally enabled by default.
باز کردن سریع، پیشفرض برای malloc/realloc/free است. باز کردن آهسته، پیشفرض برای ردیابیهای پشته کشنده است. باز کردن آهسته را میتوان برای همه ردیابیهای پشته با اضافه کردن fast_unwind_on_malloc=0 به متغیر ASAN_OPTIONS در wrap.sh خود فعال کرد.