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\n", a[0]); 7 printf("%d\n", 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)
参考网址