首页 > 系统相关 >聊一聊 Valgrind 监视非托管内存泄露和崩溃

聊一聊 Valgrind 监视非托管内存泄露和崩溃

时间:2023-05-05 15:47:46浏览次数:41  
标签:int valgrind Valgrind 聊一聊 内存 main ptr 10244

一:背景

1. 讲故事

只要是程序总会出现各种莫名其妙的问题,比如:非托管内存泄露,程序崩溃,在 Windows 平台上一般用微软自家的官方工具 App Verifier 就可以洞察,那问题出在 Linux 上怎么办呢?由于 Linux 崇尚自由,需要在各种牛鬼蛇神写的非官方开源软件中寻找一个比较靠谱的,比如本篇所说的 Valgrind

个人感觉 ValgrindApp Verifer 定位是差不多的,技术上前者使用 hook 钩子,后者使用仿真cpu,有点像 windbg 的 TTD 调试,具体信息参考:https://valgrind.org/

二:Valgrind 内存洞察

1. 安装

如果你用的是 ubuntu,可以用 apt-get 直接安装,方便快捷,目前最新的版本是 3.15.0


root@skyfly-virtual-machine:/home/skyfly/Desktop# apt-get install valgrind
Reading package lists... Done
Building dependency tree       
Reading state information... Done
valgrind is already the newest version (1:3.15.0-1ubuntu9.1).
0 upgraded, 0 newly installed, 0 to remove and 23 not upgraded.

root@skyfly-virtual-machine:/home/skyfly/Desktop# valgrind --version
valgrind-3.15.0

2. 内存泄露洞察

内存泄露大多是 new/delete , malloc/free 不匹配造成的,接下来写一个不匹配的 malloc/free 观察下。


#include <iostream>
#include <stdio.h>

using namespace std;

int main(void)
{
    int *p = (int *)malloc(4);
    *p = 10;
    
    printf("p=%d", *p);

    return EXIT_SUCCESS;
}

这里使用 vscode 进行编译,怎么编译就不说了,参见上一篇,接下来用 algrind --leak-check=full ./main.out 以仿真的方式把程序跑起来,截图如下:

从图中的 HEAP SUMMARY 区域可以看到,当前有 3 个 malloc,但只有 2 个 free,而且还找到了那个没有 free 的 malloc,在代码的 main.cpp:8 行,即 int *p = (int *)malloc(4); 处。

3. 栈溢出洞察

相信经常写递归的朋友总会遇到这类问题,为了方便演示,我故意实现一个 栈上溢 的例子吧。


#include <iostream>
#include <stdio.h>

using namespace std;

int main(void)
{
    int num = 10;
    int *ptr = &num;

    ptr -= 0x40;
    *ptr = 15;

    return EXIT_SUCCESS;
}

从图中可以清晰的看到,主线程栈上的地址 0x1ffefffd5c 无法写入,还指出了在 main.cpp:12 行,即 *ptr = 15; 处。

为了方便验证,这里用 g++ 调试的方式洞察一下。


-exec p num
$5 = 10

-exec x ptr
0x7fffffffde2c:	0xf7fb0e9800007fff

-exec info reg
...
rbp            0x7fffffffdf40      0x7fffffffdf40
rsp            0x7fffffffdf20      0x7fffffffdf20
...

从输出看,ptr 已经逃出了 rsp ~ rbp 范围之内,很明显上溢了,如果用 x 命令观察的话,可以看到里面的内容就很随机,在 windbg 中用以 ??? 来表示的。


-exec x ptr
0x7fffffffde2c:	0xf7fb0e9800007fff

-exec x 0xf7fb0e9800007fff
0xf7fb0e9800007fff:	Cannot access memory at address 0xf7fb0e9800007fff

除了观察 rsp,rbp,还可以看虚拟地址中的 stack 空间。


-exec i proc mapping
process 8327
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      ...
	  0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x2d000 /usr/lib/x86_64-linux-gnu/ld-2.31.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]

4. 数组越界洞察

valgrind 这玩意也有弱鸡的时候,比如数组越界之类的问题它就搞不定,比如下面的代码:


#include <iostream>
#include <stdio.h>

using namespace std;

int main(void)
{
    int num[5] = {1, 2, 3, 4, 5};
    int num2[10];

    num[6] = 15;

    return EXIT_SUCCESS;
}

通过下面的汇编代码观察,可以看到目前分配了 0x30 = 0n48 byte 的栈空间,截图如下:

虽然 num[6] 是越界操作,但是在合理的 栈空间 内,这种仿生cpu的方式洞察不出来,App Verifier 这种 hook 的方式是没有问题的。

接下来用 valgrind 尝试一下,可以看到果然没发现任何问题,输出如下:


skyfly@skyfly-virtual-machine:~/code$ valgrind ./main.out
==10244== Memcheck, a memory error detector
==10244== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10244== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==10244== Command: ./main.out
==10244== 
==10244== 
==10244== HEAP SUMMARY:
==10244==     in use at exit: 0 bytes in 0 blocks
==10244==   total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated
==10244== 
==10244== All heap blocks were freed -- no leaks are possible
==10244== 
==10244== For lists of detected and suppressed errors, rerun with: -s
==10244== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

三:总结

总的来说,Valgrind 在洞察内存方面还是非常强大的,但也有它不能触及到的地方,熟悉它的优点和缺点,全面了解对我们调试师来说至关重要,希望本篇对你有帮助。

标签:int,valgrind,Valgrind,聊一聊,内存,main,ptr,10244
From: https://www.cnblogs.com/huangxincheng/p/17374315.html

相关文章

  • C语言中的内存管理
    C语言中定义了四个内存区间:https://mp.weixin.qq.com/s/MtwQrp752qLMwDAFrBYm0w代码区;全局变量和静态变量区;局部变量区即栈区;动态存储区即堆区。1>栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2>堆区(heap) —一般由......
  • Linux 内存管理 pt.2
    哈喽大家好我是咸鱼,在《Linux内存管理pt.1》中我们学习了什么是物理内存、虚拟内存,了解了内存映射、缺页异常等内容那么今天我们来接着学习Linux内存管理中的多级页表和大页多级页表&大页在《Linux内存管理pt.1》中我们知道了内核为每个进程都维护了一张页表,这张页表用......
  • java基础-数组的定义,静动态初始化,数组元素的相关操作、数组的内存图
    一、什么是数组数组指的是一种容器,可以用来存储同种数据类型的多个值。数组容器在存储数据的时候,需要结合隐式转换考虑。例如:int类型的数组容器,只能存储byte、short、int类型的数据。(byte<short<int<long<float<double)例如:double类型的数组容器,可以存储byte、short、int、long......
  • 聊一聊 GDB 调试程序时的几个实用命令
    一:背景1.讲故事用惯了宇宙第一的VisualStudio再用其他的开发工具还是有一点不习惯,不习惯在于想用的命令或者面板找不到,总的来说还是各有千秋吧,今天我们来聊一下几个在调试中比较实用的命令:查看内存硬件断点虚拟内存布局二:命令解读1.查看内存相信大家都知道Visual......
  • Uniapp HBuilderX 编译 运行到手机 内存不足:***** out of memory
    HBuilderX内置node版本是32位,如果遇到JavaScriptheapoutofmemory问题,可以自行下载64位的Node进行替换替换HBuilderX 内置的node.exe文件:HBuilderX\plugins\node\node.exe用自己安装的node里面的 node.exe文件即可。替换过后再次运行会提示安装对应的binding.node......
  • 小数在内存中的存取
    小数在内存中以浮点数的形式存储,浮点数和定点数是相对的。在C中使用定点数来存储short、int、long等类型的整数,使用浮点数来存储float、double类型的小数。整数和小数在内存中的存储格式是不一致的。我们通常认为浮点数和小数是等价的,没有做严格的区分,但这并不会影响到我们,原因......
  • Vmware虚拟机热添加CPU与内存
    vCenter版本:7.0.3ESXi版本:7.0.3 在配置CPU的时候,勾选EnableCPUHotPlug,这样就可以在线添加CPU而不用关机虚拟机了。在配置Memory的时候,勾选EnableMemoryHotPlug,这样就可以在线添加内存而不用关机虚拟机了。如果要降低配置,需要将虚拟机关机之后才可以操作;—————......
  • linux释放swap分区内存
    参考文档:https://blog.csdn.net/chenghuikai/article/details/77476830第一步:先执行sync命令#sync第二步:(如果仅仅是清理swap的话,这一步可以不执行)#echo3>/proc/sys/vm/drop_caches说明:**echo1:释放页面缓存echo2:释放目录文件和inodesecho3:释放所有缓存(页面缓存,目录......
  • 用了这么多年Rust终于搞明白了内存分布!
    导读Rust作为一门学习曲线十分陡峭的语言,掌握其核心基础数据结构的内存分布对学习Rust会有很大的帮助,本文由浅入深仔细介绍了Rust的各个数据结构在内存中的分布情况。Rust作为一门学习曲线十分陡峭的语言,掌握其核心基础数据结构的内存分布对学习Rust会有很大的......
  • python中如何使两个序列相加不改变内存地址的几种方式
    #方式1a=[1,2,3]print(a)#4551311680a.extend([4,5])print(a)#4551311680#方式2b=[1,2,3]print(b)#4494299456b+=[4,5,6]print(b)#4494299456#重点讲解方式2+=的方式是因为内部实现了__iadd__()魔法方法,内部行为类似于a.extend(b)。但是要区别于b=......