Valgrind

Valgrind

体系结构

Valgrind 是一套 Linux 下,开放源代码(GPL V2)的仿真调试工具的集合。Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟了一个 CPU 环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。Valgrind 的体系结构如下图所示:

在这里插入图片描述

Valgrind 包括如下一些工具:

  • Memcheck。这是 valgrind 应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。

  • Callgrind。它主要用来检查程序中函数调用过程中出现的问题。

  • Cachegrind。它主要用来检查程序中缓存使用出现的问题。

  • Helgrind。它主要用来检查多线程程序中出现的竞争问题。

  • Massif。它主要用来检查程序中堆栈使用中出现的问题。

  • Extension。可以利用 core 提供的功能,自己编写特定的内存调试工具。

Valgrind(memcheck)报错类别

Valgrind(memcheck)包含这 7 类错误:

1.illegal read/illegal write errors

Invalid read of size 4

2.use of uninitialised values

Conditional jump or move depends on uninitialised value(s)

3.use of uninitialised or unaddressable values in system calls

Syscall param write(buf) points to uninitialised byte(s)

4.illegal frees

Invalid free()

5.when a heap block is freed with an inappropriate deallocation function

Mismatched free() / delete / delete []

6.overlapping source and destination blocks

Source and destination overlap in memcpy(0xbffff294, 0xbffff280, 21)

7.memory leak detection

​ 7.1 Still reachable

​ A start-pointer or chain of start-pointers to the block is found.memcheck won’t report

unless –show-reachable=yes is specified

​ 内存指针还在还有机会使用或者释放,指针指向的动态内存还没有被释放就退出了

​ 7.2 Definitely(明确地) lost

​ no pointer to the block can be found memcheck won’t report such blocks individually

unless –show-reachable=yes is specified

​ 确定的内存泄露,已经不能够访问这块内存

​ 7.3 Indirectly lost (cover case 4,9)

​ the block is lost, not because there are no pointers to it, but rather because all the blocks

that point to it are themselves lost

​ 指向该内存的指针都位于内存泄露处

​ 7.4 Possibly lost

​ a chain of one or more pointers to the block has been found, but at least one of the pointers is an interior-pointer

​ 可能的内存泄露,仍然存在某个指针能够访问某快内存,但该指针指向的已经不是该内存首位置

Valgrind 使用

1.编译执行程序

为了使 valgrind 发现的错误更精确,如能够定位到源代码行,建议在编译时加上-g参数,编译优化选项请选择 O0,虽然这会降低程序的执行效率。

这里用到的示例程序文件名为:test.c(如下所示),选用的编译器为 gcc。生成可执行程序

#include <stdio.h>
#include <stdlib.h>
void fun( )
{
	int *p = (int *)malloc(10*sizeof(int));
    p[10] = 0;
}

int main(void)
{
	fun();
	return 0;
}

第二步:在 valgrind 下,运行可执行程序。

利用 valgrind 调试内存问题,不需要重新编译源程序,它的输入就是二进制的可执行程序。调用 Valgrind 的通用格式是:

valgrind [valgrind-options] your-prog [your-prog-options]

Valgrind 的参数分为两类,一类是 core 的参数,它对所有的工具都适用;另外一类就是具体某个工具如 memcheck 的参数。Valgrind 默认的工具就是 memcheck,也可以通过“–tool=tool name”指定其他的工具。Valgrind 提供了大量的参数满足你特定的调试需求,具体可参考其用户手册。

这个例子将使用 memcheck,于是可以输入命令:valgrind ./test

第三步:分析 valgrind 的输出信息。

以下是运行上述命令后的输出。

valgrind --leak-check=full ./test
==20433== Memcheck, a memory error detector
==20433== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==20433== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==20433== Command: ./test
==20433== 
==20433== Invalid write of size 4
==20433==    at 0x108668: fun() (test.cpp:6)
==20433==    by 0x108679: main (test.cpp:11)
==20433==  Address 0x5235068 is 0 bytes after a block of size 40 alloc'd
==20433==    at 0x4C32FB5: malloc (vg_replace_malloc.c:380)
==20433==    by 0x10865B: fun() (test.cpp:5)
==20433==    by 0x108679: main (test.cpp:11)
==20433== 
==20433== 
==20433== HEAP SUMMARY:
==20433==     in use at exit: 40 bytes in 1 blocks
==20433==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==20433== 
==20433== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==20433==    at 0x4C32FB5: malloc (vg_replace_malloc.c:380)
==20433==    by 0x10865B: fun() (test.cpp:5)
==20433==    by 0x108679: main (test.cpp:11)
==20433== 
==20433== LEAK SUMMARY:
==20433==    definitely lost: 40 bytes in 1 blocks
==20433==    indirectly lost: 0 bytes in 0 blocks
==20433==      possibly lost: 0 bytes in 0 blocks
==20433==    still reachable: 0 bytes in 0 blocks
==20433==         suppressed: 0 bytes in 0 blocks
==20433== 
==20433== For lists of detected and suppressed errors, rerun with: -s
==20433== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
  • 左边显示类似行号的数字(32372)表示的是 Process ID。

  • 上述示例valgrind 通过运行被测试程序,发现的内存问题。通过阅读这些信息,可以发现:

    1. 这是一个对内存的非法写操作,非法写操作的内存是 4 bytes。

    2. 发生错误时的函数堆栈,以及具体的源代码行号。

    3. 非法写操作的具体地址空间。

  • 最下面是对发现的内存问题和内存泄露问题的总结。内存泄露的大小(40 bytes)也能够被检测出来。

如上述valgrind的检测输出,我们可以得到该程序一处内存没有回收(40 bytes),以及一处数组越界问题(Invalid write)。

对于该程序进行修改:

#include <stdio.h>
#include<stdlib.h>
void fun( )
{
	int *p = (int *)malloc(10*sizeof(int));
//    p[10] = 0;
	free(p);
}

int main(void)
{
	fun();
	return 0;
}

重新编译,使用valgrind 检测得到:

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

可以看到检测已经没有内存泄漏及溢出问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值