【C++】C++代码动态检查
代码动态检查方式
- 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. 分析
----
未完待续