C++ 如何迭代所有malloc块(glibc)

C++ 如何迭代所有malloc块(glibc),c++,debugging,gdb,malloc,C++,Debugging,Gdb,Malloc,我正在尝试迭代所有竞技场中的所有malloc_块。(基于核心文件进行调试,用于内存泄漏和内存损坏调查) 正如我所知,每个竞技场都有top_块,它指向一个竞技场内的top_块,基于top_块,在它的内部,有prev_大小和大小,基于代码(glibc/malloc/malloc.c): 我可以得到之前的连续块,然后在一个竞技场中循环所有块。(我可以用大小和数字统计数据块,如WinDBG:!heap-stat-h),还可以根据上一个大小和大小检查数据块是否损坏 在arena(malloc_状态)中,有

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

正如我所知,每个竞技场都有top_块,它指向一个竞技场内的top_块,基于top_块,在它的内部,有prev_大小和大小,基于代码(glibc/malloc/malloc.c): 我可以得到之前的连续块,然后在一个竞技场中循环所有块。(我可以用大小和数字统计数据块,如WinDBG:!heap-stat-h),还可以根据上一个大小和大小检查数据块是否损坏

在arena(malloc_状态)中,有一个成员变量:next which point to next arena。然后我可以循环所有竞技场的区块

但我遇到的一个问题是,如果没有分配块,上一个大小无效,如何获取上一个malloc_块??或者这种方式是不正确的


问题背景:

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

我们的做法和结果:

  • 我们使用valrgind在测试集群中重现bug,但不幸的是我们什么也得不到

  • 我试图更多地研究堆,尝试分析堆块,并遵循我以前在WinDBG中所做的方法(WinDBG中有非常有趣的堆命令来挖掘内存泄漏和内存损坏),但我被我提出的问题所阻碍

  • 我们使用valgrind massif来分析分配(我认为它非常详细和有趣,可以显示哪个分配占用了多少内存)。Massif显示了一些线索,我们按照这个检查代码,最终发现了漏洞(一个地图非常巨大,在正确使用它时,但我会在holder类的析构函数中删除,这就是为什么valgrind不报告这个)


  • 我将深入了解gdb堆源代码,以了解更多关于glic malloc结构的信息。

    首先,在深入了解
    malloc
    的实现细节之前,最好使用类似于或甚至在环境变量下运行的工具,让内部堆一致性检查为您完成工作

    但是,既然你问了……

    glibc's对查看前一块有一些有用的评论

    其中一些特别有趣的是:

    /*请注意,我们甚至不能查看prev,除非它未使用*/

    以及:

    如果为任何给定的块设置了prev\u inuse,则无法确定上一个块的大小,甚至在尝试这样做时可能会出现内存寻址错误。

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

    虽然这对您的情况没有帮助,但您可以按照
    prev\u-inuse
    宏的操作来检查前一个块是否正在使用

    #define PREV_INUSE 0x1
    #define prev_inuse(p) ((p)->size & PREV_INUSE)
    
    它检查当前块大小的低位。(所有数据块大小都可以被4整除,因此较低的2位可以用作状态。)这将帮助您在进入无人区之前停止迭代

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


    如果你真的想迭代所有的块,我建议您从
    malloc\u state::top
    开始,然后按照
    next\u chunk
    操作,直到
    next\u chunk
    指向
    top

    尝试
    pmap-XX
    命令,从不同方面跟踪内存使用情况。

    免费开源程序为glibc malloc提供您想要的功能。只需抓取一个内核(因为内核崩溃,或者使用gcore或使用gdb中的generate命令抓取一个lib内核)。然后通过执行以下操作打开核心:

    chap yourCoreFileName
    
    到达chap提示符后,如果要遍历所有块(包括自由块和非自由块),可以根据所需的详细程度执行以下任何操作,但请记住,chap中的“分配”不包含块头,而是从malloc返回的地址开始

    请尝试以下任一操作:

    count allocations
    summarize allocations
    describe allocations
    show allocations
    
    count used
    summarize used
    describe used
    show used
    
    count leaked
    summarize leaked
    describe leaked
    show leaked
    
    如果您只关心当前正在使用的分配,请尝试以下任一操作:

    count allocations
    summarize allocations
    describe allocations
    show allocations
    
    count used
    summarize used
    describe used
    show used
    
    count leaked
    summarize leaked
    describe leaked
    show leaked
    
    如果您只关心泄漏的分配,请尝试以下任一操作:

    count allocations
    summarize allocations
    describe allocations
    show allocations
    
    count used
    summarize used
    describe used
    show used
    
    count leaked
    summarize leaked
    describe leaked
    show leaked
    
    以上提到的github URL提供的文档中提供了更多详细信息


    在损坏方面,chap在启动时进行一些检查,并报告多种损坏,尽管输出有时可能有点神秘。

    这是GDB问题或WinDbg问题,但我认为不能两者兼而有之。尽管如此,我还是建议删除WinDbg标签(“核心转储”和“竞技场”在我看来不像WinDbg术语)是的,这是一个gdb问题,而不是WinDbg问题。你可能对
    gdb堆
    项目感兴趣,该项目包括在gdb中运行的Python代码,它知道如何解析glibc malloc竞技场。@TomTromey,是的,Tom我知道这个项目,并试图使用它,但不幸的是运行时错误弹出。稍后我将在gdb堆中挖掘更多关于源代码的信息。@orbitcowboy,thx,我们已经将cppcheck集成到我们的项目中,但没有发现漏洞。thx Sean,我不确定我是否理解您提到的方式,“如果你真的想迭代所有的块,我建议你从malloc_state::top开始,然后跟随下一个_块,直到下一个_块指向顶部。,tmalloc_state::top不是第一个块,而是物理上的最后一个块。我试图用valgrind复制这个bug,不幸的是,没有泄漏报告。在我们的一个数据节点中报告了错误,该节点将运行几天,然后内存达到限制。我们必须花时间来复制它。