android studio中使用asan检测内存问题

常俊侠
2023-12-01

ASan 是一种基于编译器的快速检测工具,用于检测原生代码中的内存错误。

 

ASan 可以检测以下问题:

  • 堆栈和堆缓冲区上溢/下溢
  • 释放之后的堆使用情况
  • 超出范围的堆栈使用情况
  • 重复释放/错误释放

 

build.gradle

参考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

 在 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)

wrap.sh

从 Android O MR1(API 级别 27)开始,应用可以提供可封装或替换应用进程的封装 Shell 脚本。这样,应用就可对其应用启动过程进行自定义,比如修改ASAN_OPTIONS,以便在生产设备上使用 ASan。

  1. 将 android:debuggable 和 android:extractNativeLibs=true添加到应用Manifest.xml
  2. 将 ASan 运行时库添加到应用模块的 jniLibs 中。
  3. 将包含以下内容的 wrap.sh 文件添加到每个相同的目录中。

一定要建立目录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.

 

 类似资料: