Valgrind——c/c++内存检测工具

文章目录

  • 前言
  • 检测说明
  • 泄露类型说明
  • memcheck指令
  • references


前言

Valgrind 是一个用于构建动态分析工具的检测框架。

Valgrind包含了可以自动检测多种内存管理和线程错误的工具,并对程序进行详细的分析。而且,还可以使用Valgrind来构建新工具。


检测说明

Valgrind是检测内存泄露工具,可检测如下几种内存泄露风险

No. type
1 Illegal read / Illegal write errors
2 Use of uninitialized values
3 Use of uninitialized or unaddressable values in system calls
4 Illegal frees
5 When a heap block is freed with an inappropriate deallocation function
6 Overlapping source and destination blocks
7 Fishy argument values

泄露类型说明

编译时注意加-g选项

  1. Illegal read / Illegal write errors
    表示续写了还未分配的内存块、读写已经被free的内存块或内存访问越界(包括超出堆中内存块的范围、访问了栈中不能访问的区域)。使用–read-var-info=yes选项可直详细原因。
int main()
{
    void* p = malloc(1);
    free(p);
    *(char*)p = '2';
}
==40816== Invalid write of size 1
==40816==    at 0x1091D3: main (test.cpp:22)
==40816==  Address 0x4ddfc80 is 0 bytes inside a block of size 1 free'd
==40816==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==40816==    by 0x1091CE: main (test.cpp:21)
==40816==  Block was alloc'd at
==40816==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==40816==    by 0x1091BE: main (test.cpp:20)
  1. Use of uninitialized values
    检测是否使用未初始化的值。有两种未初始化的成因:(1)函数中的局部变量没有被初始化。类的成员为基本类型,默认构造函数则什么也不做,如果直接使用该类对象的值;(2)堆上的内存块,在使用之前没有被初始化。使用malloc或new/new[]基本类型则返回的内存块为随机值。使用选项–track-origins=yes可知详细原因
class test
{
public:
    int a;
    int b;
    void* c;
public:
    test(/* args */) = default;
    ~test() = default;
};

int main()
{
    test t;
    printf("%d, %p\n", t.a, t.c);
}

编译时注意加-g选项

==40576== Conditional jump or move depends on uninitialised value(s)
==40576==    at 0x4B0FE85: __vfprintf_internal (vfprintf-internal.c:1516)
==40576==    by 0x4AFA79E: printf (printf.c:33)
==40576==    by 0x1091DE: main (test.cpp:21)
==40576==  Uninitialised value was created by a stack allocation
==40576==    at 0x1091A9: main (test.cpp:19)
  1. Use of uninitialized or unaddressable values in system calls
    检测系统调用是否已经初始化。如果要读程序提供的buffer,会检测buffer是否addressable以及是否初始化。如果要写程序提供的buffer,会检查buffer是否addressable。

  2. Illegal free
    检测是否重复释放内存块,或者指针没有指向内存的起始位置

int main()
{
    void* p = malloc(1);
    free(p);
    free(p);
}
==41017== Invalid free() / delete / delete[] / realloc()
==41017==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==41017==    by 0x1091DA: main (test.cpp:22)
==41017==  Address 0x4ddfc80 is 0 bytes inside a block of size 1 free'd
==41017==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==41017==    by 0x1091CE: main (test.cpp:21)
==41017==  Block was alloc'd at
==41017==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==41017==    by 0x1091BE: main (test.cpp:20)
  1. When a heap block is freed with an inappropriate deallocation function
    c++内存申请和释放的配对要求(进一步体现了c++的复杂性)
分配函数 释放函数
malloc, calloc, realloc, valloc, memalign free
new delete
new[] delete[]
  1. Overlapping source and destination blocks
    检测内存覆盖,及memcpy, strcpy, strncpy, strcat, strncat等函数的源和目的内存块是否有重叠。如果这些函数的源内存块和目的内存块有重叠,结果可能出错。
#define ADDR_ADD(addr, num) ((char*)addr + num)
int main()
{
    void* p = malloc(10);
    strncpy(ADDR_ADD(p, 1), (const char*)p, 5);
    free(p);
}
==41569== Conditional jump or move depends on uninitialised value(s)
==41569==    at 0x484F02A: strncpy (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==41569==    by 0x1091FE: main (test.cpp:25)
  1. Fishy argument values
    检测需要的内存大小是否是负数或者过大
==41798== Argument 'size' of function malloc has a fishy (possibly negative) value: -10
==41798==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==41798==    by 0x1091C0: main (test.cpp:25)

memcheck指令

分析内存泄露问题建议在终端中输入以下命令,可输出检测log文件

valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --log-file=res.log ./a.out

1--tool=memcheck: (--tool=[default: memcheck])表示使用memcheck工具,默认是使用memcheck
2--leak-check=full: (--leak-check=[default:summary])决定了输出泄露结果时,输出的内容。no:没输出,summary:只输出统计结果,yes和full输出详细内容
3-show-leak-kinds=all(--show-leak-kinds=[default:definite, possible]) valgrind有4种泄露类型,这个参数决定显示哪些类型泄露。可以设置多个以逗号相隔,也可以用all表示全部类型,none表示不显示
4--log-file=log(--log-file=[default:2, stderr])valgrind打印log转存到指定文件。如果未使用这个参数valgrind的log会连同程序的log一起输出


references

https://valgrind.org/

你可能感兴趣的:(C,其它,C++,内存检测,C/C++)