代码动态检查方式
- AddressSanitizer (ASan) 内存地址溢出检测器
- LeakSanitizer (LSan) 内存泄露检测器
- ThreadSanitizer (TSan) 线程互斥检测器
- UndefinedBehaviorSanitizer (UBSsan) 没有定义的行为检测器
- MemorySanitizer (MSan) 内存未初始化读取检测器
一、内存地址溢出检测器
1. 安装内存地址溢出检测库
yum install libasan Installed: libasan.x86_64 0:4.8.5-36.el7_6.2
2. 错误例子代码:
#include <stdio.h>
#define kBufSize 10
char gArr[kBufSize];
int main(int argc, char **argv) {
char localArr[kBufSize];
localArr[12] = 0x31;
gArr[11] = 0x32;
return gArr[11];
}
3. 编译代码(增加内存溢出检测)
gcc -o a1 addresss.c -fsanitize=address -g
4. 执行代码(检测内存溢出)
[root@VM_93_229_centos test]# ./a1
=================================================================
==6766== ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc4c525bac at pc 0x4006c6 bp 0x7ffc4c525b60 sp 0x7ffc4c525b50
WRITE of size 1 at 0x7ffc4c525bac thread T0
#0 0x4006c5 (/home/dev/test/a1+0x4006c5)
#1 0x7f5167e1c444 (/usr/lib64/libc-2.17.so+0x22444)
#2 0x400588 (/home/dev/test/a1+0x400588)
Address 0x7ffc4c525bac is located at offset 44 in frame <main> of T0's stack:
This frame has 1 object(s):
[32, 42) 'localArr'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
0x10000989cb20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cb40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cb50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cb60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10000989cb70: f1 f1 f1 f1 00[02]f4 f4 f3 f3 f3 f3 00 00 00 00
0x10000989cb80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cb90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cbb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000989cbc0: 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
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==6766== ABORTING
5. 分析内存溢出信息
错误信息显示变量 localArr 在内存指针 0x4006c6 处发生内存溢出错误。
通过内存地址找到源码错误行。
[root@VM_93_229_centos test]# addr2line -e ./a1 0x4006c6
/home/dev/test/addresss.c:9
[root@VM_93_229_centos test]# cat -n addresss.c
1 #include <stdio.h>
2
3 #define kBufSize 10
4
5 char gArr[kBufSize];
6
7 int main(int argc, char **argv) {
8 char localArr[kBufSize];
9 localArr[12] = 0x31;
10 gArr[11] = 0x32;
11 return gArr[11];
12 }
总结:修改localArr的内存溢出错误后,使用同样的方法监测gArr的内存溢出错误并修改。
二、内存泄露检测器
1. 安装内存泄露检测库
2. 错误例子代码
#include <stdio.h>
int main(){
int *ptr= new int(10);
return 0;
}
3. 编译代码(增加内存泄露检测器)
gcc leak.c -fsanitize=leak
4. 执行代码(检测内存泄露)
5. 分析
三、线程安全检测器
1. 安装线程安全检测库
yum install libtsan Package libtsan-4.8.5-36.el7_6.2.x86_64 already installed and latest version
2. 错误例子代码
#include <pthread.h>
#include <stdio.h>
int global;
void *Thread1(void *x) {
global++;
return NULL;
}
void *Thread2(void *x) {
global--;
return NULL;
}
int main() {
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, NULL);
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
}
3. 编译代码(增加线程安全检测器)
gcc -o t tt.c -fsanitize=thread -fPIE -pie -g
4. 执行代码(检测内存泄露)
[root@centos test]# ./t
==================
WARNING: ThreadSanitizer: data race (pid=9271)
Read of size 4 at 0x7fc3c0c85068 by thread T1:
#0 Thread1 /home/dev/test/tt.c:7 (exe+0x0000000009ed)
#1 __tsan_write_range ??:0 (libtsan.so.0+0x00000001b1d9)
Previous write of size 4 at 0x7fc3c0c85068 by thread T2:
#0 Thread2 /home/dev/test/tt.c:12 (exe+0x000000000a68)
#1 __tsan_write_range ??:0 (libtsan.so.0+0x00000001b1d9)
Thread T1 (tid=9272, running) created by main thread at:
#0 pthread_create ??:0 (libtsan.so.0+0x00000001f42b)
#1 main /home/dev/test/tt.c:18 (exe+0x000000000ab5)
Thread T2 (tid=9273, running) created by main thread at:
#0 pthread_create ??:0 (libtsan.so.0+0x00000001f42b)
#1 main /home/dev/test/tt.c:19 (exe+0x000000000ad6)
SUMMARY: ThreadSanitizer: data race /home/dev/test/tt.c:7 Thread1
==================
ThreadSanitizer: reported 1 warnings
5. 错误分析
错误显示文件tt.c的第7行和第12行有线程对data race操作(即:线程不安全操作)。
#0 Thread1 /home/dev/test/tt.c:7 (exe+0x0000000009ed) #0 Thread2 /home/dev/test/tt.c:12 (exe+0x000000000a68)
四、内存未初始化之前读取检测器
1. 安装检测库
2. 错误例子代码
#include <iostream>
int main(int argc, char** argv) {
int* a = new int[10];
a[5] = 0;
if (a[argc])
std::cout << a[3];
return 0;
}
3. 编译代码(增加内存泄露检测器)
gcc mm.c -fsanitize=memory -fPIE -pie -fno-omit-frame-pointer -g
4. 执行代码(检测内存泄露)
5. 分析
----
未完待续