Fork me on GitHub

【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. 分析

 

 ----

未完待续

posted @ 2021-08-18 13:49  Mr.YF  阅读(732)  评论(0编辑  收藏  举报