动态库单独添加Address Sanitizer
原文地址:https://www.cnblogs.com/liqinglucky/p/address-sanitizer-in-library.html
Address Sanitizer集成的原理是在汇编过程中(参考:程序编译过程与运行时内存 - liqinglucky - 博客园 (cnblogs.com))编译出.o
文件时就将AddressSanitizer的运行时库替换malloc()/free()实现内存检测功能的。所以可以单独在执行程序(main executable)加Address Sanitizer,也可以在链接库中单独加Address Sanitizer。
main executable sanitized as well or only the shared library
也就是说当软件是由一个main函数调用很多动态库(也是自己源码)生成的可执行程序,那编译时main函数有编译进address senitizer库检测内存,那些被调用的动态库源码GCC编译时也要单独 加address senitizer参数编译才能检测动态库的内存。如果只在main程序加了address senitizer参数编译,就会出现main程序内存问题能发现,有些调用的动态库内存问题不会发现。为了验证这一想法我用一个由main程序调用动态库的代码做演示。
源代码:Address-Sanitizer-C-Language: 内存泄漏/越界检查工具 - Gitee.com
一、主程序加Address Sanitizer参数编译
代码
在how_to_integration/CMakeLists.txt
加上编译参数
project( app )
//加上编译参数
add_compile_options(-fsanitize=address -fsanitize-recover=all -fsanitize=leak)
add_link_options(-fsanitize=address -fsanitize-recover=all -fsanitize=leak)
1 主程序的测试代码
/Address-Sanitizer-C-Language# git diff how_to_integration/main.c
diff --git a/how_to_integration/main.c b/how_to_integration/main.c
index 0010f95..0dabebe 100755
--- a/how_to_integration/main.c
+++ b/how_to_integration/main.c
@@ -7,7 +7,7 @@ int main(void)
printf("add:%d \n", add(a,b));
printf("sub:%d \n", sub(a,b));
+ int a1[10] = {0};
+ printf("%s a1 %d\n", __FUNCTION__, a1[11]);
return 0;
}
2 库程序的测试代码
/Address-Sanitizer-C-Language# git diff how_to_integration/lib/add.c
diff --git a/how_to_integration/lib/add.c b/how_to_integration/lib/add.c
index 96d8ea7..ed007f8 100755
--- a/how_to_integration/lib/add.c
+++ b/how_to_integration/lib/add.c
@@ -2,5 +2,8 @@
int add(int a, int b)
{
+ int a1[10] = {0};
+ printf("%s a1 %d\n", __FUNCTION__, a1[11]);
return a+b;
}
编译
build# cmake ..
build# make
build# ./app
测试
1 检测主程序的测试代码
/Address-Sanitizer-C-Language/how_to_integration/build# ./app
add:6
sub:2
=================================================================
==352812==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffee86702fc at pc 0x5591df96445c bp 0x7ffee8670280 sp 0x7ffee8670270
READ of size 4 at 0x7ffee86702fc thread T0
#0 0x5591df96445b in main (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x145b)
#1 0x7f3d2a8a6082 in __libc_start_main ../csu/libc-start.c:308
#2 0x5591df9641cd in _start (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x11cd)
Address 0x7ffee86702fc is located in stack of thread T0 at offset 92 in frame
#0 0x5591df964298 in main (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x1298)
This frame has 1 object(s):
[48, 88) 'a1' (line 10) <== Memory access at offset 92 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x145b) in main
Shadow bytes around the buggy address:
0x10005d0c6000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10005d0c6050: 00 00 00 00 f1 f1 f1 f1 f1 f1 00 00 00 00 00[f3]
0x10005d0c6060: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c6090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d0c60a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==352812==ABORTING
2 检测库程序的测试代码
/Address-Sanitizer-C-Language/how_to_integration/build# ./app
=================================================================
==352873==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffee9e7d24c at pc 0x7fa8c086b397 bp 0x7ffee9e7d1d0 sp 0x7ffee9e7d1c0
READ of size 4 at 0x7ffee9e7d24c thread T0
#0 0x7fa8c086b396 in add (/Address-Sanitizer-C-Language/how_to_integration/build/bin/libmath.so+0x1396)
#1 0x558b93e3f231 in main (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x1231)
#2 0x7fa8c069c082 in __libc_start_main ../csu/libc-start.c:308
#3 0x558b93e3f14d in _start (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x114d)
Address 0x7ffee9e7d24c is located in stack of thread T0 at offset 92 in frame
#0 0x7fa8c086b228 in add (/Address-Sanitizer-C-Language/how_to_integration/build/bin/libmath.so+0x1228)
This frame has 1 object(s):
[48, 88) 'a1' (line 5) <== Memory access at offset 92 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/Address-Sanitizer-C-Language/how_to_integration/build/bin/libmath.so+0x1396) in add
Shadow bytes around the buggy address:
0x10005d3c79f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x10005d3c7a40: f1 f1 f1 f1 00 00 00 00 00[f3]f3 f3 f3 f3 00 00
0x10005d3c7a50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10005d3c7a90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==352873==ABORTING
二、库程序加Address Sanitizer参数编译
代码
在how_to_integration/lib/CMakeLists.txt
加上编译参数
//加上编译参数
add_compile_options(-fsanitize=address -fsanitize-recover=all -fsanitize=leak)
add_link_options(-fsanitize=address -fsanitize-recover=all -fsanitize=leak)
1 主程序的测试代码
/Address-Sanitizer-C-Language# git diff how_to_integration/main.c
diff --git a/how_to_integration/main.c b/how_to_integration/main.c
index 0010f95..0dabebe 100755
--- a/how_to_integration/main.c
+++ b/how_to_integration/main.c
@@ -7,7 +7,7 @@ int main(void)
printf("add:%d \n", add(a,b));
printf("sub:%d \n", sub(a,b));
+ int a1[10] = {0};
+ printf("%s a1 %d\n", __FUNCTION__, a1[11]);
return 0;
}
2 库程序的测试代码
/Address-Sanitizer-C-Language# git diff how_to_integration/lib/add.c
diff --git a/how_to_integration/lib/add.c b/how_to_integration/lib/add.c
index 96d8ea7..ed007f8 100755
--- a/how_to_integration/lib/add.c
+++ b/how_to_integration/lib/add.c
@@ -2,5 +2,8 @@
int add(int a, int b)
{
+ int a1[10] = {0};
+ printf("%s a1 %d\n", __FUNCTION__, a1[11]);
return a+b;
}
编译
在库程序单独加编译参数-fsanitize=address
编译时需要在编译环境上加环境变量
build# export ASAN_OPTIONS=verify_asan_link_order=0
然后编译
build# cmake ..
build# make
Scanning dependencies of target math
[ 20%] Building C object bin/CMakeFiles/math.dir/add.o
[ 40%] Building C object bin/CMakeFiles/math.dir/sub.o
[ 60%] Linking C shared library libmath.so
[ 60%] Built target math
[ 80%] Linking C executable app
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tmpnam' is dangerous, better use `mkstemp'
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tempnam' is dangerous, better use `mkstemp'
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tmpnam_r' is dangerous, better use `mkstemp'
[100%] Built target app
测试
1 检测主程序的测试代码
/Address-Sanitizer-C-Language/how_to_integration/build# cmake ..
/Address-Sanitizer-C-Language/how_to_integration/build# make
Scanning dependencies of target math
[ 20%] Building C object bin/CMakeFiles/math.dir/add.o
[ 40%] Building C object bin/CMakeFiles/math.dir/sub.o
[ 60%] Linking C shared library libmath.so
[ 60%] Built target math
[ 80%] Linking C executable app
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tmpnam' is dangerous, better use `mkstemp'
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tempnam' is dangerous, better use `mkstemp'
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tmpnam_r' is dangerous, better use `mkstemp'
[100%] Built target app
/Address-Sanitizer-C-Language/how_to_integration/build# ./app
add:6
sub:2
main a1 1382831681 <<< 主程序不检测, 说明库程序的编译参数并未在主程序生效
2 检测库程序的测试代码
/Address-Sanitizer-C-Language/how_to_integration/build# ./app
=================================================================
==352965==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc0218bfcc at pc 0x7f3b9539e397 bp 0x7ffc0218bf50 sp 0x7ffc0218bf40
READ of size 4 at 0x7ffc0218bfcc thread T0
#0 0x7f3b9539e396 in add (/Address-Sanitizer-C-Language/how_to_integration/build/bin/libmath.so+0x1396)
#1 0x55a7479e11e0 in main (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x11e0)
#2 0x7f3b951bd082 in __libc_start_main ../csu/libc-start.c:308
#3 0x55a7479e10ed in _start (/Address-Sanitizer-C-Language/how_to_integration/build/app+0x10ed)
Address 0x7ffc0218bfcc is located in stack of thread T0 at offset 92 in frame
#0 0x7f3b9539e228 in add (/Address-Sanitizer-C-Language/how_to_integration/build/bin/libmath.so+0x1228)
This frame has 1 object(s):
[48, 88) 'a1' (line 5) <== Memory access at offset 92 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/Address-Sanitizer-C-Language/how_to_integration/build/bin/libmath.so+0x1396) in add
Shadow bytes around the buggy address:
0x1000004297a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000004297b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000004297c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000004297d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000004297e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x1000004297f0: f1 f1 f1 f1 00 00 00 00 00[f3]f3 f3 f3 f3 00 00
0x100000429800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000429810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000429820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000429830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000429840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==352965==ABORTING
遇到的问题
1 程序运行失败:ASan runtime does not come first in initial library list
/Address-Sanitizer-C-Language/how_to_integration/build# make
Scanning dependencies of target math
[ 20%] Building C object bin/CMakeFiles/math.dir/add.o
[ 40%] Building C object bin/CMakeFiles/math.dir/sub.o
[ 60%] Linking C shared library libmath.so
[ 60%] Built target math
Scanning dependencies of target app
[ 80%] Building C object CMakeFiles/app.dir/main.o
[100%] Linking C executable app
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tmpnam' is dangerous, better use `mkstemp'
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tempnam' is dangerous, better use `mkstemp'
/usr/bin/ld: /lib/x86_64-linux-gnu/libasan.so.5: warning: the use of `tmpnam_r' is dangerous, better use `mkstemp'
[100%] Built target app
/Address-Sanitizer-C-Language/how_to_integration/build# ./app
==343885==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
调查:
2 c - valgrind asan runtime does not come first in initial library list - Stack Overflow
3 c++ - CLion wont run binary with address sanitizer - Stack Overflow
4 单独在库里编译Address Sanitizer:gcc - Asan : Issue with asan library loading - Stack Overflow
main executable sanitized as well or only the shared library
建议方法:
- build main executable with -fsanitize=address
- get rid of /etc/ld.so.preload on your test machine
- disable the check (need recent GCC) with export ASAN_OPTIONS=verify_asan_link_order=0; but you have to be sure that libraries from /etc/ld.so.preload do not intercept symbols important for Asan e.g. malloc, free, etc., otherwise things will start breaking