官方资料如下:
https://developer.android.com/ndk/guides/asan#cmake
源码:
我使用的是AS4.1.3,创建一个native c++工程,在native-lib.cpp中敲入如下代码:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_android_1native_1c_1plus_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
int * array = new int[100];
delete []array;
int a = array[3];
return env->NewStringUTF(hello.c_str());
}
第一个坑:运行程序后,界面一直白屏,不显示"Hello from C++"
看logcat中的报错,提示 wrap.sh:No such file or directory。
排查后发现 wrap.sh不能使用windows格式,要使用Unix格式,需要在linux下创建这个文件。
第二个坑:发现在data/app/com.example.android_native_c_plus-Nyg7hV9kFawcUYOu3KHx7A==/lib/arm64下找不到wrap.sh
需要手动push wrap.sh到该目录,需要root后才能执行此操作
第三个坑:wrap.sh中的allow_user_segv_handler不能设置为0
设置为0会报segment错误
第四个坑:报错的信息是一个字符串,没有定位到具体的代码
成功运行范例后,报错如下:
05-08 11:01:57.249 12171 12171 I wrap.sh : =================================================================
05-08 11:01:57.250 12171 12171 I wrap.sh : ==12181==ERROR: AddressSanitizer: heap-use-after-free on address 0x003f000018ac at pc 0x007122b4fc6c bp 0x007fc92e9990 sp 0x007fc92e9970
05-08 11:01:57.250 12171 12171 I wrap.sh : READ of size 4 at 0x003f000018ac thread T0 (d_native_c_plus)
05-08 11:01:57.269 12171 12171 I wrap.sh : #0 0x7122b4fc6b (/data/app/com.example.android_native_c_plus-Nyg7hV9kFawcUYOu3KHx7A==/lib/arm64/libnative-lib.so+0x1c6b)
05-08 11:01:57.269 12171 12171 I wrap.sh : #1 0x7122d5809f (/data/app/com.example.android_native_c_plus-Nyg7hV9kFawcUYOu3KHx7A==/oat/arm64/base.odex+0x1309f)
需要把app\build\intermediates\cmake\debug\obj\arm64-v8a这个目录下生成的带符号信息的so,放到linux底下,然后执行
aarch64-linux-gnu-addr2line -f -C -e libnative-lib.so 0x1c6b
得到结果如下:
Java_com_example_android_1native_1c_1plus_MainActivity_stringFromJNI
E:\android\android_native_c_plus\app\.cxx\cmake\debug\arm64-v8a/E:/android/android_native_c_plus/app/src/main/cpp/native-lib.cpp:11
对应代码中的:int a = array[3];
第五个坑:无法检测内存泄漏
在wrap.sh中增加detect_leaks=1如下:
#!/system/bin/sh
HERE="$(cd "$(dirname "$0")" && pwd)"
export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1,detect_leaks=1
ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so)
if [ -f "$HERE/libc++_shared.so" ]; then
export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
else
export LD_PRELOAD="$ASAN_LIB"
fi
"$@"
结果输出:
I wrap.sh : ==12943==AddressSanitizer: detect_leaks is not supported on this platform.
我的平台是RK 3368,不支持内存泄漏检测
第六个坑:不要加-O1
网上有文章建议说可以选择加上-O1或更高级别的编译,加了之后AddressSantitizer就不起作用了,不能加-O1。
彩蛋:在linux下使用g++/gcc编译时,也可以使用AddressSanitizer进行内存泄漏检测
注意在编译和链接时都需要打开AddressSanitizer
LN_OPT=-lpthread -fsanitize=address -fno-omit-frame-pointer
CC_OPT=-g -fsanitize=address -fno-omit-frame-pointer