valgrind使用简介
1、问题
虽然C/C++是一种非常有用且功能强大的语言,但很难调试。 某些时候可能遇到内存错误。 如果知道出错 ,或者程序一直崩溃,我们可以用gdb/DBX去调试。 但是,有时遇到的问题是由于内存错误造成的,但它不出段错误,很多时候,我们不希望海里捞针,在gdb中设置很多断点,逐步盘查。 还有可能会遇到的另一个问题是内存泄漏:在某个地方,调用malloc分配的内存没有调用free来释放。 Valgrind是一个可以帮助解决这两个问题的程序
2、valgrind功能介绍
Valgrind是一个构建动态分析工具的工具框架,其带有一组工具,每个都执行某种调试,分析或类似的任务,可帮助开发者改进程序。 Valgrind的架构是模块化的,因此可以轻松创建新工具,而不会影响现有结构。标准提供了许多有用的工具。
- Memcheck是一个内存错误检测器。它可以帮助您使您的程序更加正确,特别是使用C和C ++编写的程序。
- Cachegrind是一个缓存和分支预测分析器。它可以帮助您使程序运行得更快。
- Callgrind是一个调用图生成缓存分析器。它与Cachegrind有一些重叠,但也收集了一些Cachegrind没有的信息。
- Helgrind是一个线程错误检测器。它可以帮助您使多线程程序更加正确。
- DRD也是一个线程错误检测器。它与Helgrind类似,但使用不同的分析技术,因此可能会发现不同的问题。
- Massif是一个堆分析器。它可以帮助您使您的程序使用更少的内存。
- DHAT是一种不同类型的堆分析器。它可以帮助您了解块寿命,块利用率和布局低效问题。
- SGcheck是一个可以检测堆栈和全局数组溢出的实验工具。它的功能与Memcheck的功能是互补的:SGcheck发现了Memcheck无法解决的问题,反之亦然。
- BBV是一个实验性的SimPoint基本块矢量生成器。对于从事计算机体系结构研究和开发的人员非常有用。
在这里,我们主要讨论内存错误检测器(Memcheck),用于检测C/C ++程序中常见问题:
- 访问不应该使用的内存,例如溢出,堆溢出,溢出栈顶,在访问释放了的内存。
- 使用未定义的值,即尚未初始化的值或从其他未定义值派生的值。
- 错误地释放堆内存,如重复释放堆,或者不匹配的使用malloc/new/new []与free/delete/delete []
- 在memcpy和相关函数中重叠src和dst指针。
- 在调用内存分配函数时,给size参数传递一个负值。
- 内存泄漏。
像这些问题有时候很难通过其他方式发现,常常长时间未被发现,然后导致偶然的,难以诊断的崩溃。Memcheck还使用命令行选项--xtree-memory和monitor命令xtmemory,对执行树提供内存分析。
3、内存泄露
在这个例子中,释放缓存的逻辑已经被注释,所以产生一个内存泄露的问题。
#define SNPRINTF_ATTR(fmt_pos, firstarg_pos) \
__attribute__ ((format(vsnprintf, fmt_pos, firstarg_pos))) #include <stdio.h>
#include <stdarg.h>
#include <stdlib.h> using namespace std;
class query_buffer {
private:
char *buf;
size_t len;
size_t cap; public:
query_buffer(): len(), cap() {
buf = (char *)calloc(cap, sizeof(char));
}; virtual ~query_buffer() {
//if (buf) free(buf);
len = ;
cap = ;
}; void resize_if_needed(size_t new_len) {
if (new_len >= cap) {
while (new_len > cap) cap *= ;
buf = (char *)realloc(buf, cap*sizeof(char));
}
else if ( * new_len < cap) {
cap /= ;
buf = (char *)realloc(buf, cap*sizeof(char));
}
}; int append(const char *fmt, ...) SNPRINTF_ATTR(, ) {
//resize_if_needed(len + max_print_len);
va_list args;
va_start(args, fmt);
int n = vsnprintf(buf + len, static_cast<int>(cap - len), fmt, args);
if (n>=) len += n;
va_end(args);
return n;
}; const char *get_buf() {
return this->buf;
};
}; int main(void) {
query_buffer query_buffer;
query_buffer.resize_if_needed(); int n = query_buffer.append("%d: %s -- %s, %s\n",
, "engineer", "office", "computer?");
n += query_buffer.append("%d: %s -- %s, %s\n",
, "chef", "kitchen", "oven?");
n += query_buffer.append("%d: %s -- %s, %s\n",
, "gardener", "yard", "yard?");
n += query_buffer.append("%d: %s -- %s, %s\n",
, "nurse", "hospital", "patient?");
printf("Total size %d:\n%s", n, query_buffer.get_buf());
}
编译后,运行程序querybuf:
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./querybuf
==== Memcheck, a memory error detector
==== Copyright (C) -, and GNU GPL'd, by Julian Seward et al.
==== Using Valgrind-3.10. and LibVEX; rerun with -h for copyright info
==== Command: ./a.out
====
Total size :
: engineer -- office, (what wrong with the computer?)
: chef -- kitchen, (what wrong with the oven?)
: gardener -- yard, (what wrong with the yard?)
: nurse -- hospital, (what wrong with the patient?)
====
==== FILE DESCRIPTORS: open at exit.
==== Open file descriptor : /dev/pts/
==== <inherited from parent>
====
==== Open file descriptor : /dev/pts/
==== <inherited from parent>
====
==== Open file descriptor : /dev/pts/
==== <inherited from parent>
====
====
==== HEAP SUMMARY:
==== in use at exit: , bytes in blocks
==== total heap usage: allocs, frees, , bytes allocated
====
==74342== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 1
==74342== at 0x4C2BB4A: realloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==74342== by 0x400B38: query_buffer::resize_if_needed(unsigned long) (tryvarargs.cpp:32)
==74342== by 0x4008B5: main (tryvarargs.cpp:53)
====
==== LEAK SUMMARY:
==== definitely lost: , bytes in blocks
==== indirectly lost: bytes in blocks
==== possibly lost: bytes in blocks
==== still reachable: bytes in blocks
==== suppressed: bytes in blocks
====
==== For counts of detected and suppressed errors, rerun with: -v
==== ERROR SUMMARY: errors from contexts (suppressed: from )
从上述报错信息可知,realloc的内存没有释放造成内存泄露。这指向释放realloc分配内存的地方有问题--〉类的destructor。
4、读写过界
下面例子有两个问题:
- 字符串数组分配了10个元素,但是在符值时有11个
- 用malloc分配的内存却用delete来释放。
int main(void) {
char *buf = (char *)calloc(, sizeof(char));
for (int i = ; i < ; ++i)
buf[i] = static_cast<char>('a' + i);
printf("%s", buf);
delete buf;
}
我们运行valgrind来查一下内存:valgrind --tool=memcheck ./heapoverflow
==== Memcheck, a memory error detector
==== Copyright (C) -, and GNU GPL'd, by Julian Seward et al.
==== Using Valgrind-3.10. and LibVEX; rerun with -h for copyright info
==== Command: ./heapoverflow
====
==== Invalid write of size
==== at 0x400A3B: main (tryvarargs.cpp:)
==== Address 0x5a1304a is bytes after a block of size alloc'd
==== at 0x4C2B974: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==== by 0x400A1A: main (tryvarargs.cpp:)
====
==101781== Invalid read of size 1
==101781== at 0x569CA94: vfprintf (in /usr/lib64/libc-2.17.so)
==101781== by 0x56A5C18: printf (in /usr/lib64/libc-2.17.so)
==101781== by 0x400A5C: main (tryvarargs.cpp:68)
==101781== Address 0x5a1304a is 0 bytes after a block of size 10 alloc'd
==101781== at 0x4C2B974: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==101781== by 0x400A1A: main (tryvarargs.cpp:63)
====
==== Invalid read of size
==== at 0x56CD4FE: _IO_default_xsputn (in /usr/lib64/libc-2.17.so)
==== by 0x56CB551: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib64/libc-2.17.so)
==== by 0x569CA4C: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x56A5C18: printf (in /usr/lib64/libc-2.17.so)
==== by 0x400A5C: main (tryvarargs.cpp:)
==== Address 0x5a1304a is bytes after a block of size alloc'd
==== at 0x4C2B974: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==== by 0x400A1A: main (tryvarargs.cpp:)
====
==101781== Mismatched free() / delete / delete []
==101781== at 0x4C2B131: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==101781== by 0x400A68: main (tryvarargs.cpp:69)
==101781== Address 0x5a13040 is 0 bytes inside a block of size 10 alloc'd
==101781== at 0x4C2B974: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==101781== by 0x400A1A: main (tryvarargs.cpp:63)
====
abcdefghijk====
==== HEAP SUMMARY:
==== in use at exit: bytes in blocks
==== total heap usage: allocs, frees, bytes allocated
====
==== All heap blocks were freed -- no leaks are possible
====
==== For counts of detected and suppressed errors, rerun with: -v
==== ERROR SUMMARY: errors from contexts (suppressed: from )
输出中已经高亮显示的报错指出:
Invalid read of size 1
Mismatched free() / delete / delete []
5、在memcpy和相关函数中重叠src和dst指针
类似memcpy使用中重叠内存而出错的问题,不光是刚刚接触c/c++的程序员会犯,许多工作多年的高手也会犯同样问题。有时候是对库函数的定义和限制不清楚,有时候就是疏忽了。而这种问题特别难发现。valgrind的报告可以帮助我们找到问题:
int main(void) {
char *buf = (char *)calloc(, sizeof(char));
for (int i = ; i < ; ++i)
buf[i] = static_cast<char>('a' + i);
printf("%s", buf);
char *dest = buf+;
memcpy(dest, buf, 6);
printf("%s", dest);
free(buf);
}
$ valgrind --tool=memcheck ./heapoverflow
==== Memcheck, a memory error detector
==== Copyright (C) -, and GNU GPL'd, by Julian Seward et al.
==== Using Valgrind-3.10. and LibVEX; rerun with -h for copyright info
==== Command: ./heapoverflow
====
==103964== Source and destination overlap in memcpy(0x5a13043, 0x5a13040, 6)
==103964== at 0x4C2E1DC: memcpy@@GLIBC_2.14 (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==103964== by 0x400AF0: main (tryvarargs.cpp:72)
====
abcdefghijabcdefj====
==== HEAP SUMMARY:
==== in use at exit: bytes in blocks
==== total heap usage: allocs, frees, bytes allocated
====
==== All heap blocks were freed -- no leaks are possible
====
==== For counts of detected and suppressed errors, rerun with: -v
==== ERROR SUMMARY: errors from contexts (suppressed: from )
参考文献
[1] http://cs.ecs.baylor.edu/~donahoo/tools/valgrind/
[2] http://pages.cs.wisc.edu/~bart/537/valgrind.html
[3] https://www.thegeekstuff.com/2011/11/valgrind-memcheck/
[4] http://valgrind.org/docs/manual/manual.html
valgrind使用简介的更多相关文章
- 【调试】Linux下超强内存检测工具Valgrind
[调试]Linux下超强内存检测工具Valgrind 内容简介 Valgrind是什么? Valgrind的使用 Valgrind详细教程 1. Valgrind是什么? Valgrind是一套Lin ...
- Valgrind简介:
Valgrind是动态分析工具的框架.有很多Valgrind工具可以自动的检测许多内存管理和多进程/线程的bugs,在细节上剖析你的程序.你也可以利用Valgrind框架来实现自己的工具. Valgr ...
- Valgrind检测内存泄露简介
原文地址: Valgrind 概述 体系结构 Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合.Valgrind由内核(core)以及基于内核的其他调试工具组成.内核 ...
- Valgrind简介
Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具.
- valgrind简介以及在ARM上交叉编译运行【转】
转自:https://blog.csdn.net/dengcanjun6/article/details/54958359 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...
- valgrind 的使用简介
zz自 http://blog.csdn.net/destina/article/details/6198443 感谢作者的分享! 一 valgrind是什么? Valgrind是一套Linux下 ...
- Valgrind使用[转]
简介 调试程序有很多方法,例如向屏幕上打印消息,使用调试器,或者只需仔细考虑程序如何运行,并对问题进行有根有据的猜测. 在修复 bug 之前,首先要确定在源程序中的位置.例如,当一个程序产生崩溃或生成 ...
- linux下valgrind的使用概述
Valgrind简介: Valgrind是动态分析工具的框架.有很多Valgrind工具可以自动的检测许多内存管理和多进程/线程的bugs,在细节上剖析你的程序.你也可以利用Valgrind框架来实现 ...
- 在ARM Linux 使用 Valgrind
Linux valgrind 移植到ARM-Linux 一.Cross-Compile/交叉编译 (1)下载及解压Valgrind-3.11 (2)修改confirure 将armv7*)修改为ar ...
随机推荐
- 使用 libffi 实现 AOP
核心还是利用oc消息的查找派发机制,进行类结构的动态修改,用新函数替换老函数,然后再调用老函数. 前言 众所周知,使用runtime的提供的接口,我们可以设定原方法的IMP,或交换原方法和目标 ...
- 一些需要禁用的PHP危险函数
phpinfo()功能描述:输出 PHP 环境信息以及相关的模块.WEB 环境等信息.危险等级:中 passthru()功能描述:允许执行一个外部程序并回显输出,类似于 exec().危险等级:高 e ...
- Docker实战(六)之使用Dockerfile创建镜像
Dockervile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义镜像. 1.基本结构 Dockerfile由一行行命令语句组成,并且支持以#开头的注释行. 一般而言,Do ...
- 记录一下mac上码云的使用
项目比较多的时候用第三方的托管平台管理自己的代码还是挺不错的,记录一下码云的基本使用 分两部分进行说明: 一 :怎么上传自己本地的代码到码云.(方式,通过终端输入命令行) 具体的步骤: 1 :首先得在 ...
- 流程一直处于Running状态,应该怎么停止?
流程一直处于Running状态,应该怎么停止? 概述 我们有遇到这种情况:可能由于某些原因,流程发起后一直处于Running状态,然后我们想Stop掉这些出问题的流程,这个时候你在Workspace里 ...
- gitblit-1.8.0域认证
gitblit-1.8.0\data\defaults.properties # # DEFAULTS.PROPERTIES # # The default Gitblit settings. # # ...
- 《Effective C++》item25:考虑写出一个不抛异常的swap函数
std::swap()是个很有用的函数,它可以用来交换两个变量的值,包括用户自定义的类型,只要类型支持copying操作,尤其是在STL中使用的很多,例如: int main(int argc, _T ...
- Linux入门基础(三):Linux用户及权限基础
用户基础 用户和组 每个用户都拥有一个userid 每个用户都属于一个主组,属于一个或多个附属组 每个组拥有一个groupid 每个进程以一个用户身份运行,受该用户可访问资源限制 每个可登陆用户拥有一 ...
- 各类分布----二项分布,泊松分布,负二项分布,gamma 分布,高斯分布,学生分布,Z分布
伯努利实验: 如果无穷随机变量序列 是独立同分布(i.i.d.)的,而且每个随机变量 都服从参数为p的伯努利分布,那么随机变量 就形成参数为p的一系列伯努利试验.同样,如果n个随机变量 独立同 ...
- [TJOI2014]Alice and Bob[拓扑排序+贪心]
题意 给出一个序列的以每一项结尾的 \(LIS\) 的长度a[],求一个序列,使得以每一项为开头的最长下降子序列的长度之和最大. \(n\leq 10^5\) . 分析 最优解一定是一个排列,因为如果 ...