C++软件开发常用辅助软件——Valgrind

Valgrind

Valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具。该工具内部又包含多个子工具集(如memcheck, cachegrind, callgrind, helgrind等等),每个子工具集相互独立,每一次分析只能选择一个子工具,默认子工具为memcheck。

用法

valgrind [valgrind-options] [your-program] [your-program-options]

示例

演示代码:

1 #include <stdio.h>
2 
3 int main()
4 {
5     int *a = new int[3];
6     printf("%d
", a[0]);
7     printf("%d
", a[4]);
8     return 0;
9 }

显然上述代码存在3处问题。

1. 第5行申请的内存未释放

2. 第6行访问了未初始化的变量

3. 第7行访问了非法地址

运行检测工具

valgrind ./a.out

输出如下

 1 ==6945== Memcheck, a memory error detector
 2 ==6945== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
 3 ==6945== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
 4 ==6945== Command: ./a.out
 5 ==6945== 
 6 ==6945== Conditional jump or move depends on uninitialised value(s)
 7 ==6945==    at 0x57BF132: vfprintf (in /lib64/libc-2.26.so)
 8 ==6945==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
 9 ==6945==    by 0x4005D3: main (in /home/nosoul/DEV/test/a.out)
10 ==6945== 
11 ==6945== Use of uninitialised value of size 8
12 ==6945==    at 0x57BAF3B: _itoa_word (in /lib64/libc-2.26.so)
13 ==6945==    by 0x57BE820: vfprintf (in /lib64/libc-2.26.so)
14 ==6945==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
15 ==6945==    by 0x4005D3: main (in /home/nosoul/DEV/test/a.out)
16 ==6945== 
17 ==6945== Conditional jump or move depends on uninitialised value(s)
18 ==6945==    at 0x57BAF45: _itoa_word (in /lib64/libc-2.26.so)
19 ==6945==    by 0x57BE820: vfprintf (in /lib64/libc-2.26.so)
20 ==6945==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
21 ==6945==    by 0x4005D3: main (in /home/nosoul/DEV/test/a.out)
22 ==6945== 
23 ==6945== Conditional jump or move depends on uninitialised value(s)
24 ==6945==    at 0x57BE8D8: vfprintf (in /lib64/libc-2.26.so)
25 ==6945==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
26 ==6945==    by 0x4005D3: main (in /home/nosoul/DEV/test/a.out)
27 ==6945== 
28 ==6945== Conditional jump or move depends on uninitialised value(s)
29 ==6945==    at 0x57BF32C: vfprintf (in /lib64/libc-2.26.so)
30 ==6945==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
31 ==6945==    by 0x4005D3: main (in /home/nosoul/DEV/test/a.out)
32 ==6945== 
33 0
34 ==6945== Invalid read of size 4
35 ==6945==    at 0x4005DC: main (in /home/nosoul/DEV/test/a.out)
36 ==6945==  Address 0x5b38c90 is 4 bytes after a block of size 12 alloc'd
37 ==6945==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
38 ==6945==    by 0x4005B8: main (in /home/nosoul/DEV/test/a.out)
39 ==6945== 
40 0
41 ==6945== 
42 ==6945== HEAP SUMMARY:
43 ==6945==     in use at exit: 12 bytes in 1 blocks
44 ==6945==   total heap usage: 3 allocs, 2 frees, 73,740 bytes allocated
45 ==6945== 
46 ==6945== LEAK SUMMARY:
47 ==6945==    definitely lost: 12 bytes in 1 blocks
48 ==6945==    indirectly lost: 0 bytes in 0 blocks
49 ==6945==      possibly lost: 0 bytes in 0 blocks
50 ==6945==    still reachable: 0 bytes in 0 blocks
51 ==6945==         suppressed: 0 bytes in 0 blocks
52 ==6945== Rerun with --leak-check=full to see details of leaked memory
53 ==6945== 
54 ==6945== Use --track-origins=yes to see where uninitialised values come from
55 ==6945== For lists of detected and suppressed errors, rerun with: -s
56 ==6945== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)

检测结果先看“HEAP SUMMARY”开始往后的内容。参考第52行以及第54的提示,因此我们运行

valgrind --track-origins=yes --leak-check=full ./a.out

输出如下

 1 ==7080== Memcheck, a memory error detector
 2 ==7080== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
 3 ==7080== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
 4 ==7080== Command: ./a.out
 5 ==7080== 
 6 ==7080== Conditional jump or move depends on uninitialised value(s)
 7 ==7080==    at 0x57BF132: vfprintf (in /lib64/libc-2.26.so)
 8 ==7080==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
 9 ==7080==    by 0x4005D3: main (test.cpp:6)
10 ==7080==  Uninitialised value was created by a heap allocation
11 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
12 ==7080==    by 0x4005B8: main (test.cpp:5)
13 ==7080== 
14 ==7080== Use of uninitialised value of size 8
15 ==7080==    at 0x57BAF3B: _itoa_word (in /lib64/libc-2.26.so)
16 ==7080==    by 0x57BE820: vfprintf (in /lib64/libc-2.26.so)
17 ==7080==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
18 ==7080==    by 0x4005D3: main (test.cpp:6)
19 ==7080==  Uninitialised value was created by a heap allocation
20 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
21 ==7080==    by 0x4005B8: main (test.cpp:5)
22 ==7080== 
23 ==7080== Conditional jump or move depends on uninitialised value(s)
24 ==7080==    at 0x57BAF45: _itoa_word (in /lib64/libc-2.26.so)
25 ==7080==    by 0x57BE820: vfprintf (in /lib64/libc-2.26.so)
26 ==7080==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
27 ==7080==    by 0x4005D3: main (test.cpp:6)
28 ==7080==  Uninitialised value was created by a heap allocation
29 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
30 ==7080==    by 0x4005B8: main (test.cpp:5)
31 ==7080== 
32 ==7080== Conditional jump or move depends on uninitialised value(s)
33 ==7080==    at 0x57BE8D8: vfprintf (in /lib64/libc-2.26.so)
34 ==7080==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
35 ==7080==    by 0x4005D3: main (test.cpp:6)
36 ==7080==  Uninitialised value was created by a heap allocation
37 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
38 ==7080==    by 0x4005B8: main (test.cpp:5)
39 ==7080== 
40 ==7080== Conditional jump or move depends on uninitialised value(s)
41 ==7080==    at 0x57BF32C: vfprintf (in /lib64/libc-2.26.so)
42 ==7080==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
43 ==7080==    by 0x4005D3: main (test.cpp:6)
44 ==7080==  Uninitialised value was created by a heap allocation
45 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
46 ==7080==    by 0x4005B8: main (test.cpp:5)
47 ==7080== 
48 0
49 ==7080== Invalid read of size 4
50 ==7080==    at 0x4005DC: main (test.cpp:7)
51 ==7080==  Address 0x5b38c90 is 4 bytes after a block of size 12 alloc'd
52 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
53 ==7080==    by 0x4005B8: main (test.cpp:5)
54 ==7080== 
55 0
56 ==7080== 
57 ==7080== HEAP SUMMARY:
58 ==7080==     in use at exit: 12 bytes in 1 blocks
59 ==7080==   total heap usage: 3 allocs, 2 frees, 73,740 bytes allocated
60 ==7080== 
61 ==7080== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
62 ==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
63 ==7080==    by 0x4005B8: main (test.cpp:5)
64 ==7080== 
65 ==7080== LEAK SUMMARY:
66 ==7080==    definitely lost: 12 bytes in 1 blocks
67 ==7080==    indirectly lost: 0 bytes in 0 blocks
68 ==7080==      possibly lost: 0 bytes in 0 blocks
69 ==7080==    still reachable: 0 bytes in 0 blocks
70 ==7080==         suppressed: 0 bytes in 0 blocks
71 ==7080== 
72 ==7080== For lists of detected and suppressed errors, rerun with: -s
73 ==7080== ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 0 from 0)

第6行访问了未初始化的变量的相关检测如下(1个问题有时会多次检测出来)

==7080== Conditional jump or move depends on uninitialised value(s)
==7080==    at 0x57BF32C: vfprintf (in /lib64/libc-2.26.so)
==7080==    by 0x57C69B5: printf (in /lib64/libc-2.26.so)
==7080==    by 0x4005D3: main (test.cpp:6)
==7080==  Uninitialised value was created by a heap allocation
==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==7080==    by 0x4005B8: main (test.cpp:5)

第7行访问了非法地址的检测如下

==7080== Invalid read of size 4
==7080==    at 0x4005DC: main (test.cpp:7)
==7080==  Address 0x5b38c90 is 4 bytes after a block of size 12 alloc'd
==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==7080==    by 0x4005B8: main (test.cpp:5)

第5行申请的内存未释放的检测如下

==7080== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==7080==    at 0x4C2F06F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==7080==    by 0x4005B8: main (test.cpp:5)

将bug都修复了,再次运行检测工具,输出如下

==7313== Memcheck, a memory error detector
==7313== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7313== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==7313== Command: ./a.out
==7313== 
0
==7313== 
==7313== HEAP SUMMARY:
==7313==     in use at exit: 0 bytes in 0 blocks
==7313==   total heap usage: 3 allocs, 3 frees, 73,740 bytes allocated
==7313== 
==7313== All heap blocks were freed -- no leaks are possible
==7313== 
==7313== For lists of detected and suppressed errors, rerun with: -s
==7313== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

参考网址

原文地址:https://www.cnblogs.com/NoSoul/p/13356082.html