valgrind使用
参数配置
gcc
-g:
增加调试信息,供valgrind精确定位。-O0:
关闭gcc优化;优化产生的代码可能会造成valgrind误判。
valgrind
--leak-check=full
no: 不进行内存泄露检测; summary: 显示内存泄露情况; full:不仅显示内存泄露,还显示出错代码。
--show-reachable=yes
详细显示still reachable 和 indirectly lost两种类型的内存泄露,默认不显示;如case1和case4。
内存泄露
内存泄露: 由于疏忽或错误造成程序未能释放已经不能再使用的内存。 —— 维基百科
指针
start-pointer:
指向内存起始位置 interior-pointer:
指向内存中间位置
泄露类型
possibly lost:
指针指向内存的内部位置。
still reachable:
程序运行结束后,虽然没有被释放,但仍然可以访问。
definitely lost:
内存无法被访问。
indirectly lost:
虽然有地址指向该空间,但已经无法被访问了。
泄露举例
Pointer chain AAA Leak Case BBB Leak Case
------------- ------------- -------------
(1) RRR ------------> BBB DR
(2) RRR ---> AAA ---> BBB DR IR
(3) RRR BBB DL
(4) RRR AAA ---> BBB DL IL
(5) RRR ------?-----> BBB (y)DR, (n)DL
(6) RRR ---> AAA -?-> BBB DR (y)IR, (n)DL
(7) RRR -?-> AAA ---> BBB (y)DR, (n)DL (y)IR, (n)IL
(8) RRR -?-> AAA -?-> BBB (y)DR, (n)DL (y,y)IR, (n,y)IL, (_,n)DL
(9) RRR AAA -?-> BBB DL (y)IL, (n)DL
Pointer chain legend:
- RRR: a root set node or DR block
- AAA, BBB: heap blocks
- --->: a start-pointer
- -?->: an interior-pointer
Leak Case legend:
- DR: Directly reachable
- IR: Indirectly reachable
- DL: Directly lost
- IL: Indirectly lost
- (y)XY: it's XY if the interior-pointer is a real pointer
- (n)XY: it's XY if the interior-pointer is not a real pointer
- (_)XY: it's XY in either case
case1: RRR ---> BBB
void *RRR;
int main()
{
RRR = malloc(8);
return 0;
}
==1244== LEAK SUMMARY:
==1244==still reachable
: 8 bytes in 1 blocks
case2: RRR ---> AAA ---> BBB
void **RRR;
int main()
{
RRR = (void**)malloc(8);
*RRR = malloc(8);
return 0;
}
==1345== LEAK SUMMARY:
==1345==still reachable
: 16 bytes in 2 blocks
case3:RRR BBB
int main()
{
void *RRR = malloc(8);
return 0;
}
==1400== LEAK SUMMARY:
==1400==definitely lost
: 8 bytes in 1 blocks
case4:RRR AAA ---> BBB
int main()
{
void **RRR = (void**)malloc(8);
*RRR = malloc(8);
return 0;
}
==1461== LEAK SUMMARY:
==1461==definitely lost
: 8 bytes in 1 blocks
==1461==indirectly lost
: 8 bytes in 1 blocks
case5:RRR -?-> BBB
void *RRR;
int main()
{
RRR = malloc(8);
RRR = (char*)RRR + 2;
return 0;
}
==1530== LEAK SUMMARY:
==1530==possibly lost
: 8 bytes in 1 blocks
case6:RRR ---> AAA -?-> BBB
void **RRR;
int main()
{
RRR = (void**)malloc(8);
*RRR = malloc(8);
*RRR = (char*)(*RRR) + 2;
return 0;
}
==1587== LEAK SUMMARY:
==1587==possibly lost
: 8 bytes in 1 blocks
==1587==still reachable
: 8 bytes in 1 blocks
case7:RRR -?-> AAA ---> BBB
void **RRR;
int main()
{
RRR = (void**)malloc(8);
*RRR = malloc(8);
RRR = (void**)((char*)RRR + 1);
return 0;
}
==1642== LEAK SUMMARY:
==1642==possibly lost
: 16 bytes in 2 blocks
case8:RRR -?-> AAA -?-> BBB
void **RRR;
int main()
{
RRR = (void**)malloc(8);
*RRR = malloc(8);
*RRR = ((char*)(*RRR) + 1);
RRR = (void**)((char*)RRR + 1);
return 0;
}
==1776== LEAK SUMMARY:
==1776==possibly lost
: 16 bytes in 2 blocks
case9:RRR AAA -?-> BBB
int main()
{
void **RRR = (void**)malloc(8);
*RRR = malloc(8);
*RRR = ((char*)(*RRR) + 1);
return 0;
}
==3856== LEAK SUMMARY:
==3856==definitely lost
: 8 bytes in 1 blocks
==3856==indirectly lost
: 8 bytes in 1 blocks
内存错误
读写越界
8 int *arr = new int[2];
9 arr[2] = 2;
10 arr[0] = arr[2];
11
12 delete [] arr;
==2371== Invalid write of size 4
==2371== at 0x80485FD: main (test.cpp:9)
==2371==
==2371== Invalid read of size 4
==2371== at 0x8048607: main (test.cpp:10)
NOTE: 如果在栈空间上申请数组arr, valgrind没有
检测出读写越界。详见原理简述
地址重叠
8 char *str = new char[10];
9 char *src = str;
10 char *dst = str + 2;
11 memcpy(dst, src, 4);
12
13 delete [] str;
==2413== Source and destination overlap in memcpy(0x433902a, 0x4339028, 4)
==2413== at 0x402EE13: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2413== by 0x8048654: main (test.cpp:11)
多次释放
8 char *str = new char[10];
9 char *rep = str;
10
11 delete [] str;
12 delete [] rep;
==2440== Invalid free() / delete / delete[] / realloc()
==2440== at 0x402BD38: operator delete
==2440== by 0x8048623: main (test.cpp:12)
==2440== Address 0x4339028 is 0 bytes inside a block of size 10 free’d
==2440== at 0x402BD38: operator delete
==2440== by 0x8048610: main (test.cpp:11)
==2440== HEAP SUMMARY:
==2440== in use at exit: 0 bytes in 0 blocks
==2440== total heap usage:1 allocs, 2 frees,
10 bytes allocated
分配尺寸错误
9 int *arr = new int[-1];
10 delete [] arr;
==2496== Argument ‘size’ of function __builtin_vec_new has a fishy (possibly negative) value:
-1
==2496== at 0x402ADFC: operator new (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2496== by 0x80485F1: main (test.cpp:9)
释放内部指针
int main()
{
void *RRR = malloc(10);
RRR = (char*)RRR + 1;
free(RRR);
}
==3953== HEAP SUMMARY:
==3953== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3953== at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3953== by 0x8048461: main (inter.cpp:5)
==3953==
==3953== LEAK SUMMARY:
==3953==definitely lost
: 10 bytes in 1 blocks
分配与释放函数不一致
9 int *arr = new int[10];
10
11 free(arr);
==2519== Mismatched free() / delete / delete []
==2519== at 0x402B3D8: free
==2519== by 0x8048601: main (test.cpp:11)
==2519== Address 0x4339028 is 0 bytes inside a block of size 40 alloc’d
==2519== at 0x402ADFC: operator new
==2519== by 0x80485F1: main (test.cpp:9)
原理简述
valgrind memcheck
在内部模拟一个CPU环境,所有的数据处理流程,都在内部CPU进行模拟。
valid-value (V) bits
valgrind
为程序数据流中的每个bit都关联了一个valid-value bit
(简称V),用来检测该bit是否有效。比如int val = 4
,当CPU从内存中加载val时,会同时从valid-value位图中读取32个bit;赋值操作发生时,该32个valid-value bit被设置为有效;当变量回写内存时,valid-value也会同时被写入内存。
NOTE: 数据中每个bit都会有一个V bit 与之关联,而不是对每个字节进行监控。
X = X | (1 << 3)
只对某个bit赋值。
V 设置时机
变量被赋值时。
V 检测时机
- 变量值用于生产地址
- 变量值参影响程序运行流
- 变量值用于系统调用
case1
int main()
{
int *p;
int result = *p;
}
==4413== Use of uninitialised value of size 4
==4413== at 0x80483F6: main (address.cpp:6)
case2
int main()
{
int result;
if (result == 6)
{
cout << "got" << endl;
}
}
==4436== Conditional jump or move depends on uninitialised value(s)
==4436== at 0x80486BB: main (address.cpp:8)
如果未初始化变量不进行分支决策,则不会报错。
int main()
{
int arr[2];
int result;
for (size_t i = 0; i < 2; i++)
{
result += arr[i];
}
return 0;
}
==1169== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
case3
int main()
{
int result;
exit(result);
}
==4450== Syscall param exit_group(status) contains uninitialised byte(s)
==4450== at 0x41DBBD4: _Exit (_exit.S:33)
疑问:
为什么不是每次使用变量的时候,都进行有效检测?
解释: 正如官方文档所说,C语言中涉及内存地址对齐
struct S { int x; char c};
struct S s1, s2;
s1.x = 0;
s1.c = ' ';
s2 = s1;
结构体S涉及内存对齐,大小为8个字节。s1
中,末尾的3个字节V
始终是无效,如果在赋值的时候也进行检测,则会报错,实际上却没有必要。
valid-address (A) bits
valgrind
为程序中的每个地址都关联了一个valid-address
(简称A),用于检测地址是否有效。每个字节对应一个V bit。
A bit 设置时机
- 程序启动时,全局数据区域设置为可访问。
- 调用new/malloc时,将分配空间设置为可访问;delete/free时,设置为不可访问。
- 函数调用栈,栈指针
SP
与BP
之间的位置,被设置为可访问。栈回收时,设置为不可访问。 - 某些系统调用。如mmap,进行内存映射。
函数栈
int main()
{
int arr[2];
arr[2] = 2;
}
==1125== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
NOTE: 栈上的读写越界检测不出来
A bit 检测时机
当读写内存时,查询A bit,检测读写地址是否有效。
V & A
V: 数据是否有效
A: 地址是否有效
NOTE: calloc 会同时设置A & V bit,calloc返回后,将区间内容设置为0。
valgrind使用的更多相关文章
- 使用valgrind检查内存
Valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,是公认的最接近Purify的产品,它包含一个内核——一个软件合成的CPU,和一系列的小工具,每个工具都可以完成一项任务——调试 ...
- 【转】 如何使用Valgrind memcheck工具进行C/C++的内存泄漏检测
系统编程中一个重要的方面就是有效地处理与内存相关的问题.你的工作越接近系统,你就需要面对越多的内存问题.有时这些问题非常琐碎,而更多时候它会演变成一个调试内存问题的恶梦.所以,在实践中会用到很多工具来 ...
- linux下内存泄露检测工具Valgrind介绍
目前在linux开发一个分析实时路况的应用程序,在联合测试中发现程序存在内存泄露的情况. 这下着急了,马上就要上线了,还好发现了一款Valgrind工具,完美的解决了内存泄露的问题. 推荐大家可以使用 ...
- Valgrind 发现程序的内存问题
参考 : [1]. 应用 Valgrind 发现 Linux 程序的内存问题. http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/ [2 ...
- Valgrind 3.11.0编译安装
Valgrind 3.11.0编译安装 Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind遵守GNU通用公共许可证条款,是一款自由软件. 到3.3.0版本为 ...
- valgrind检查C++内存泄漏
valgrind --tool=memcheck --leak-check=full ./httptest Valgrind 使用 用法: valgrind [options] prog-and-ar ...
- Valgrind的多线程调试工具
Valgrind的多线程调试工具 Helgrind是Valgrind的一个重点功能 本节主要针对与多线程基本安全问题进行检测:[所有的代码环境都是在POSIX_THREAD模式下] 写线程代码时 经 ...
- 交叉编译mips平台上valgrind
STEP 1:下载最新版本的valgrind:http://www.valgrind.org/downloads/valgrind-3.9.0.tar.bz2 目前支持的平台,在官网上列表如下:{x8 ...
- HTTP(socket)下载遇到valgrind提示的错误: Conditional jump or move depends on uninitialised value(s)
我写了个http下载函数,下载txt.jpg都正常,就是下载php有问题:valgrind会报错Conditional jump or move depends on uninitialised va ...
- Valgrind简单用法
Valgrind的主要作者Julian Seward刚获得了今年的Google-O'Reilly开源大奖之一──Best Tool Maker.让我们一起来看一下他的作品.Valgrind是运行在Li ...
随机推荐
- PG进程结构和内存结构
本文主要介绍PostgreSQL数据库(后文简称PG)进程结构和内存结构,物理结构将在后续继续整理分享. 上图描述了PG进程结构.内存结构和部分物理结构的内容.图中的内容包含了两个部分: PG ...
- 一、spring 4概述
0 前言 0.0 Spring 来历 Spring 是于2003年兴起的一个轻量级的Java 开发框架, 为了解决企业应用开发的复杂性而创建, 核心是控制反转(IoC)和面向切面编程(AOP). 简单 ...
- 构建高可靠hadoop集群之1-理解hdfs架构
本文主要参考 http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html 主要内容是对该文 ...
- SQL:检索数据-基本检索
检索数据 1.select语句 增删改查四大操作之"查",即检索: 一般包括:what,where:查什么,从哪里选择 2.检索单个列 例:想从products表中检索名为prod ...
- Angular-chart.js 使用说明(基于angular.js工程)
Angular-chart.js是基于Chart.js的angular组件,引入项目后直接操作数据即可. 引用方法: 分别将Chart.js.angular-chart.js.angular-c ...
- YII2.0 用GII创建视图文件后访问404
使用GII的CRUD Generator创建searchModelClass 和控制器类文件,视图文件后,访问控制器地址后出现404的情况. 创建过程如图所示 后来发现是控制器类 Controller ...
- THINKPHP网站漏洞怎么修复解决
THINKPHP漏洞修复,官方于近日,对现有的thinkphp5.0到5.1所有版本进行了升级,以及补丁更新,这次更新主要是进行了一些漏洞修复,最严重的就是之前存在的SQL注入漏洞,以及远程代码执行查 ...
- 什么是mysql数据库安全 简单又通俗的mysql库安全简介
首先我们要了解一下什么是mysql数据库,mysql是目前网站以及APP应用上用的较多的一个开源的关系型数据库系统,可以对数据进行保存,分段化的数据保存,也可以对其数据进行检索,查询等功能的数据库. ...
- stm32+lwip(四):网页服务器测试
我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...
- go学习笔记-函数
函数 定义 格式 func function_name( [parameter list] ) [return_types] { 函数体 } 解析 func:函数由 func 开始声明 functio ...