扒一扒使用AddressSanitizer进行native内存泄露分析踩过的坑

官方资料如下:

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

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值