ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何排查堆问题

如何排查堆问题 1、chunk的结构代码中使用malloc申请size内存其实申请了一块size8的chunk如上图所示chunk可以分为chunk头和chunk内存(malloc返回的地址图中的mem)而chunk头就是用来排查堆越界的重点工具。chunk头为8字节前4个字节表示的是上一个chunk的大小(当前面一个chunk未使用时)当前面一个chunk使用时这4个字节就会被前一个chunk使用也就不会表示前一个chunk的大小了。后四个字节可以分为两部分低三位是PMA标志位P标记位表示前一个chunk是否使用1为使用0为未使用(前4个字节才有效)M标记表示从哪个内存区域获得的虚拟内存1表示chunk是从mmap映射区域分配的0表示从heap区域分配的。A表示该chunk属于主分配区或者非主分配区1表示为主分配区0表示非主分配区。高29位表示当前chunk的大小(字节)这个大小包括chunk头。注意当前chunk的大小不一定等于size8由于c库维护chunk的原因或者页对齐等原因。2、如何查找被踩的chunk根据core文件我们可以知道有问题的chunk的地址然后通过readelf -l core可以查看core文件的segment可以知道出问题的chunk地址处在哪个segment如图所示图中offset是文件偏移量VirtAddr是虚拟地址PhysAddr是物理地址FileSize是当前segment大小具体可以参考《程序员的自我修养》假如有问题的堆再这个segment我们可以获得以下信息如图所示那我们就可以从core文件的offset偏移处读取堆上数据可以使用以下条件判断chunk是否被踩1.如果上一个chunk未使用校验size of previous chunk(当前chunk头的前4字节)和上一个chunk的size(上一个chunk头后4字节的29位)是否相等2.chunk的size一定大于16通过这样我们大概就知道被踩chunk的地址了。3、如何找到罪魁祸首我们找到被踩chunk后我们怎么找到罪魁祸首呢这有可能是上一个chunk踩的也有可能是上上个chunk踩我们如何判断踩其他chunk的chunk是谁申请的呢1.通过被踩chunk上的内容是否有特殊字段从而判断出是谁踩的然后再去代码里读取。2.可以封装malloc函数在chunk头后再设置一个头用来保存lr(谁调用的malloc)寄存器如果是必现的问题那就可以找到是谁申请的踩人的chunk了。3.可以查找其他symbol包含这个chunk的地址symbol指的是bss段或者data段的全局变量、静态变量等。第3种方法的原理是代码中有个全局变量或者静态变量指向了踩人的chunk。第三种方法该如何使用呢首先我们使用readelf -S a.out读取可执行文件的section找到对应的.data、.bss然后读取core文件的相应的section看看里面的数据是否有被踩chunk的地址如果有的话可以找到.data或者.bss对应的虚拟地址在gdb下使用info symbol 虚拟地址就可以找到对应的变量就可以确认了。tip1:为什么chunk最小为16字节因为C库使用双向链表对chunk进行管理所以需要8字节保存指针(指向前一个chunk,指向后一个chunk)再加上chunk头正好是16字节。
返回列表