ASan 是一种基于编译器的快速检测工具,用于检测原生代码中的内存错误。
ASan 可以检测以下问题:
参考android官网的说明,在模块的 build.gradle 中增加arguments:
android {
defaultConfig {
externalNativeBuild {
cmake {
# Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
不过,我的工程里面加这个和不加好像没什么区别。因为我再defaultConfig里面已经指定了abi,这个应该不需要吧
defaultConfig {
applicationId "com.cam"
minSdkVersion 27
targetSdkVersion 27
versionCode 1
versionName "1.0.0"
ndk {
abiFilters "arm64-v8a"
}
}
在 CMakeLists.txt 中的设置compile option和link properties
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)开始,应用可以提供可封装或替换应用进程的封装 Shell 脚本。这样,应用就可对其应用启动过程进行自定义,比如修改ASAN_OPTIONS,以便在生产设备上使用 ASan。
一定要建立目录resources/lib/arm64-v8a这样的目录,将wrap.sh放在这个目录下。
#!/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
"$@"
最终目录结构应该是下面这样:
<project root>
└── app
└── src
└── main
├── jniLibs
│ ├── arm64-v8a
│ │ └── libclang_rt.asan-aarch64-android.so
│ ├── armeabi-v7a
│ │ └── libclang_rt.asan-arm-android.so
└── resources
└── lib
├── arm64-v8a
│ └── wrap.sh
├── armeabi-v7a
│ └── wrap.sh
然后就可以运行看看了,出现log中包含wrap.sh就对了。
wrap.sh : AddressSanitizer:DEADLYSIGNAL
wrap.sh : =================================================================
wrap.sh : ==26278==ERROR: AddressSanitizer: SEGV on unknown address 0x1680001e2fe602f3 (pc 0x007135a4ea48 bp 0x007fed72dac0 sp 0x007fed72d270 T0)
wrap.sh : ==26278==The signal is caused by a READ memory access.