valgrind检测内存问题的原理

1、valgrind检测原理
valgrind 是一个提供了一些 debug 和优化的工具的工具箱,可以使得你的程序减少内存泄漏或者错误访问。valgrind 默认使用 memcheck 去检查内存问题。memcheck 检测内存问题的原理如下图所示:
memcheck 能够检测出内存问题,关键在于其建立了两个全局表。
valid-value map:对于进程的整个地址空间中的每一个字节(byte),都有与之对应的 8 个 bits;对于 cpu 的每个寄存器,也有一个与之对应的 bit 向量。这些 bits 负责记录该字节或者寄存器值是否具有有效的、已初始化的值。
valid-address map:对于进程整个地址空间中的每一个字节(byte),还有与之对应的 1 个 bit,负责记录该地址是否能够被读写。在两个全局表的基础上,以如下方式进行检测:
当要读写内存中某个字节时,首先检查 valid-address map 中这个字节对应的 a bit。
如果该a bit显示该位置是无效位置,memcheck 则报告读写错误。内核(core)类似于一个虚拟的 cpu 环境,这样当内存中的某个字节被加载到真实的 cpu 中时,该字节对应的 v bit (在 valid-value map 中) 也被加载到虚拟的 cpu 环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则 memcheck 会检查对应的 v bits,如果该值尚未初始化,则会报告使用未初始化内存错误。
不过valgrind也不是万能的,对于栈上的内存空间操作就无法检测到。
2、命令选项
基本命令:valgrind --leak-check=yes ./a.out arg1 arg2
为了能够定位到源代码的行,建议编译时加上-g选项,并选择o0优化
3、使用示例
示例代码:
#include int main(){    int* x = (int*)malloc(10 * sizeof(int));    x[10] = 1; //问题1,越界了    return 0; //问题2,没有释放内存}  
执行valgrind检测后的结果:
barret@barret-pc:~$ valgrind --leak-check=yes ./a.out==393== memcheck, a memory error detector==393== copyright (c) 2002-2017, and gnu gpl'd, by julian seward et al.==393== using valgrind-3.15.0 and libvex; rerun with -h for copyright info==393== command: ./a.out==393== ==393== invalid write of size 4==393==    at 0x10916b: main (a.cpp:6)==393==  address 0x4a47068 is 0 bytes after a block of size 40 alloc'd==393==    at 0x483b7f3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)==393==    by 0x10915e: main (a.cpp:5)==393== ==393== ==393== heap summary:==393==     in use at exit: 40 bytes in 1 blocks==393==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated==393== ==393== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1==393==    at 0x483b7f3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)==393==    by 0x10915e: main (a.cpp:5)==393== ==393== leak summary:==393==    definitely lost: 40 bytes in 1 blocks==393==    indirectly lost: 0 bytes in 0 blocks==393==      possibly lost: 0 bytes in 0 blocks==393==    still reachable: 0 bytes in 0 blocks==393==         suppressed: 0 bytes in 0 blocks==393== ==393== for lists of detected and suppressed errors, rerun with: -s==393== error summary: 2 errors from 2 contexts (suppressed: 0 from 0)  
结果解析如下:
==393==:执行程序的进程id
invalid write of size 4:表示发现一个错误,这里显示源代码第6行有错误,这里很明显是越界了,所以显示invalid write错误
40 bytes in 1 blocks are definitely lost in loss record 1 of 1:内存泄露错误,泄漏的大小是10* sizeof(int)40byte。
leak summary也会显示内存泄漏的情况
4、分析常见内存问题
4.1、写入非法内存地址
上面的例子已经展示了这种情况,访问分配的内存区域之外的空间,valgrind会上报如下的错误:
invalid
write of size x
后跟调用栈信息
4.2、读取非法内存地址
和上一个情况类似,不同 的是读取而不是写入,错误信息如下:
invalid
read of size x
后跟调用栈信息
4.3、读取未初始化内存区域
#include int main(){    int* x = (int*)malloc(10 * sizeof(int));    int a = x[1] + 1; //不初始化就使用内存的值    free(x);    return a;}  
valgrind显示如下错误:
==427== syscall param exit_group(status)** contains uninitialised byte(s)**==427==    at 0x4938136: exit (exit.c:31)==427==    by 0x489bb41: __run_exit_handlers (exit.c:132)==427==    by 0x489bbdf: exit (exit.c:139)==427==    by 0x48790b9: (below main) (libc-start.c:342)  
4.4、内存双重释放
示例:
#include int main(){    int* x = (int*)malloc(10 * sizeof(int));    free(x); //free两次    free(x);    return 0;}  
valgrind显示如下错误,显示两次free的位置:


Modelithics和Qorvo大力扩展GaN RF仿真模型库
波音隐瞒MAX 737型飞机的问题遭到了股东的集体诉讼
电缆/电线的最大载流能力
送女朋友礼物排行榜,高颜值耳机分享!
2019人工智能·艺术与科技展暨数字媒体艺术教育论坛”在沪举行
valgrind检测内存问题的原理
区块链如何影响资产所有权
智能工厂时代下,食品工业智能生产提上日程
PTC线性热敏电阻工作原理
一道LeetCode的多种解法
ATA-L50水声功率放大器:可驱动水声换能器,可用于水下通信测试
承德科胜450台式真空机|熟食包装机|河北包装机
ESD保护组件的设计要求
华为mate10什么时候上市?华为mate10最新消息:华为mate10爆料不断,华为Mate9无奈提前降价!
MySQL索引的使用问题
车灯改造之氙气灯改装
移远通信全球数字经济和物联网行业发展如火如荼
饮用水管智能排水监测系统的功能优势
长江存储128层闪存今年投入技术研发和实现量产
基于微功耗IC实现延长监护仪电池寿命的方案解析