asan主要用于下面内存错误访问情况
Use after free (dangling pointer dereference)
堆上分配的空间被 free 之后再次使用
Heap buffer overflow
访问的区域在堆上, 并且超过了分配的空间
Stack buffer overflow
访问的区域在栈上, 并且超过了分配给它的空间
Memory leaks
程序结束时未释放堆上分配的内存
Double free 指针重复释放
在makefile里添加-fsanitize=address -g
如: CFLAGS += -fsanitize=address -g -fno-omit-frame-pointer -g -O0
简单的用gcc命令就行 gcc main.c -fsanitize=address -g -fno-omit-frame-pointer -g -O0 -lm -o test
CMakeLists.txt里添加
set (CMAKE_C_FLAGS_DEBUG "$CMAKE_C_FLAGS_DEBUG} -fsanitize=address -g -fno-omit-frame-pointer")
set (CMAKE_SHARED_LINKER_FLAG_DEBUG "$CMAKE_SHARED_LINKER_FLAG_DEBUG} -fsanitize=address -g -fno-omit-frame-pointer")
set (CMAKE_EXE_LINKER_FLAGS "$CMAKE_EXE_LINKER_FLAGS} -fsanitize=address -g -fno-omit-frame-pointer")
例子1
void main() {
char *a = "abcde";
char *bb = calloc(1, 5);
return;
}
编译后运行,
会提示
==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 5 bytes in 1 object allocated from
#address in main .../main.c 3
例子2
void main() {
char *a = "abcde";
char *bb = calloc(1, 5);
strcpy(bb, aa);
return;
}
则会多提示一个AddressSanitizer, heap-buffer-overflow on address...
#address in main ..... main.c 4
例子3
#include <stdio.h>
void main() {
int a[10];
a[15]=15;
printf("a[15]=%d\n",a[15)];
return;
}
则会提示AddressSanitizer: stack-buffer-overflow on address.....
#addres in main .... main.c 4
例子4
#include <string.h>
void main() {
char *aa = calloc(1, 10);
free(aa);
strcpy(aa, "abc");
}
则会提示AddressSanitizer: heap-use-after-free on address ....
#address in main.c 5 (strcpy)
freed by thread
#address in main.c 4 (free)
previously allocated by thread here
#address in main (calloc)
例子5
#include <string.h>
void main() {
char *aa = calloc(1, 10);
free(aa);
free(aa);
}
则会提示AddressSanitizer: attempting double-free on ....
#address in main 5 (第二个free)
freed by thread here
#address in main 4 (第一个free)
Android的可以参考下面的(我还试过)
Address Sanitizer | Android NDK | Android Developers
深入浅出Android NDK之ASan检测内存越界_android asan_sztaohongtao的博客-优快云博客
APP 下面的 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(${libname} PUBLIC -fsanitize=address -fno-omit-frame-pointer) set_target_properties(${libname} PROPERTIES LINK_FLAGS -fsanitize=address)
NDK-BUILD
Application.mk 文件添加:
APP_ABI := armeabi-v7a arm64-v8a (已有的,跟asan无关)
APP_STL := c++_shared # Or system, or none. APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer APP_LDFLAGS := -fsanitize=address
Android.mk 文件添加:
APP_STL := c++_shared # Or system, or none. APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer APP_LDFLAGS := -fsanitize=address
LOCAL_CFLAGS : = ...... -fsanitize=address -fno-omit-frame-pointer
LOCAL_SANITIZE := address
LOCAL_LDFLAGS += -fsanitize=address
拷贝 Asan 库到 jniLibs 目录下
Asan 库位于下面路径下:
android-ndk-rxxx/toolchains/llvm/prebuilt
ndk-build命令需要sdk大于27,且NDK_DEBUG=1
比如
ndk-build NDK_DEBUG=1 NDK_PROJECT_PAH=. APP_BUILD_SCRIPT=./build_Android.mk NDK_APPLICATION_MK=./Application.mk NDK_OUT=./out NDK_LIBS_OUT=./out/libs APP_PLATFORM=android-27
64 位 libclang_rt.asan-aarch64-android.so , 32 位 libclang_rt.asan-arm-android.so ,分别拷贝两个库到 jniLibs 相应的目录下。
这两个库可以在下面找到
Mac /Users/***/Library/Android/sdk/ndk/****/toochains/llvm/prebuilt/darwin-x86_64/lib64/clang/***/lib/linux/
Linux /home/***/android-ndk-**/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/****/lib/linux/
经验证, 下面这个不需要
新建 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
"$@"
另外还有个类似asan的工具, valgrind
命令 valgrind --tool=memcheck --leak-check=full 可执行文件名
最好是可执行文件执行一段时间后进行deinit(即有主动释放内存的),这样在deinit后valgrind就可以检测出其他尚未释放的内存或者中间有错误使用的内存