c – 如何迭代所有malloc块(glibc)

我正在尝试迭代所有竞技场中的所有malloc_chunk. (基于核心文件的调试,用于内存泄漏和内存损坏调查)

据我所知,每个竞技场都有top_chunk指向一个竞技场内部的顶部块,基于top_chunk,在它内部,有prev_size和size,基于代码(glibc / malloc / malloc.c):
《c – 如何迭代所有malloc块(glibc)》
我可以获得之前的连续块,然后在一个场地中循环所有块. (我可以统计大小和数量的块,如WinDBG:!heap -stat -h),并且还基于prev_size和size,我可以检查块是否已损坏.

在竞技场(malloc_state)中,有一个成员变量:next指向下一个竞技场.然后我可以循环所有竞技场的大块.

但我遇到的一个问题是,如果没有分配块,prev_size无效,如何获取以前的malloc_chunk?或者这种方式不正确.

问题背景:

我们遇到的内存泄漏错误是在几个在线数据节点(我们的项目是分布式存储集群)中报告的内存泄漏.

我们做了什么和结果:

>我们使用valrgind来重现测试集群中的错误,但遗憾的是我们什么都没得到.
>我试图调查关于堆的更多信息,尝试分析堆块并按照我之前在WinDBG中执行的方式(它有非常有趣的堆命令来挖掘内存泄漏和内存损坏),但我被问题阻止了我问过.
>我们使用valgrind-massif来分析分配(我认为它非常详细和有趣,可以显示哪个分配占用了多少内存). Massif显示了几条线索,我们按照这个并检查代码,最后发现泄漏(地图非常巨大,并且正确使用它,但我会删除持有者类的析构函数,这就是为什么valgrind不报告这个).

我将更多地了解gdb-heap源代码以了解更多有关glic malloc结构的信息.

最佳答案 首先,在深入研究malloc的实现细节之前,您可以更好地利用
valgrind这样的工具,甚至在
MALLOC_CHECK_环境变量下运行,让内部堆一致性检查为您完成工作.

但是,既然你问….

glibc的malloc.c有一些关于查看上一个块的有用评论.

一些特别有趣的是:

/ *请注意,我们甚至无法查看prev,除非它没有使用* /

和:

如果为任何给定的块设置了prev_inuse,那么您无法确定前一个块的大小,甚至可能在尝试执行此操作时获得内存寻址错误.

这只是malloc实施的限制.当使用前一个块时,将存储该大小的页脚由分配的用户数据使用.

虽然它对您的情况没有帮助,但您可以通过遵循prev_inuse宏的功能来检查以前的块是否正在使用.

#define PREV_INUSE 0x1
#define prev_inuse(p) ((p)->size & PREV_INUSE)

它检查当前块大小的低位. (所有块大小都可被4整除,因此较低的2位可用于状态.)这将有助于您在进入无人区之前停止迭代.

不幸的是,在访问每个块之前,你仍然会提前终止循环.

如果你真的想迭代所有块,我建议你从malloc_state :: top开始并按照next_chunk直到next_chunk指向顶部.

点赞