首页
社区
课程
招聘
[原创]通过gdb调试学习heap的基础知识
发表于: 2021-4-9 02:37 15518

[原创]通过gdb调试学习heap的基础知识

2021-4-9 02:37
15518

image-20210130081019615

首先我们现在main函数下断点,观察此时内存情况

image-20210130081151505

可以看到此时在虚拟内存中系统还没有给我们开辟堆

然后我们运行完第一个malloc之后

可以看到此时出现了一片很大的堆空间,再用heap命令观察

image-20210130112114694

image-20210130115921470

在fastbin中出现了一个0x21(33)大小的chunk,我们申请了0x10,为什么会是0x21呢,这就涉及到了一个chunk的最小大小,chunk是有格式的,由chunk头和用户数据区组成(使用中),其中chunk头由prev_size和size组成(之后会说),用户数据区才是我们申请的0x10

image-20210130082312154

我们称运行过程中被malloc分配的内存为一个chunk,这块内存在ptmalloc中用malloc_chunk结构体表示,当程序申请的chunk被free时,会被加入相应的空闲管理列表中(也就是bins)。

由上图知道,chunk由一个统一的结构体声明,但是它的神奇之处在于,在被使用时和空闲时却又有两种不同的状态

image-20210130082740170

image-20210130082801323

image-20210130083104834

prev_size:如果前一个chunk是空闲的,该域表示前一个chunk的大小,如果前一个chunk不空闲,该域无意义

chunk的复用:chunk可以使用它的下一个chunk的prev_size字段

size:当前chunk的大小,并且它的二进制的后三位为标记位,记录了当前chunk和前一个chunk的一些属性,重点是最后一位(P位)

PREV_INUSE:记录前一个chunk是否被分配

fd:指向了下一个(非物理相邻)空闲的chunk,其实也就是前一个被free的chunk

bk:指向了上一个(非物理相邻)空闲的chunk,就是后一个被free的chunk

因为bins采取链表管理,新的chunk是往前插入(伪链表头),有点类似于栈,在下边实例2可以直观看到

fd_nextsize:指向前一个与当前大小不同的第一个空闲块,不包含bin的头指针(用于large chunk)

bk_nextsize:指向了后一个与当前chunk大小不同的第一个空闲块,不包含bin的头指针(用于large chunk)

Ptmalloc使用chunk实现内存管理,对chunk的管理基于独特的边界标记法;重要的是对地址的对齐。

Ptmalloc的地址对齐方式依赖平台定义的size_t长度,对于32位平台,size_t长度为4字节,对Linux x86_64为8字节

以64位为例

prev_size = 8byte

size = 8byte

所以一个使用中的chunk的大小的计算公式应该是:

加16也就是prev_size和size的大小,减去8是因为向一个chunk“借”了8B(prev_size)

所以在64位平台上一个最小chunk的大小为0x20(chunk header+fd+bk),再加上地址的对齐因素,所以size字段的低三位永远不会被使用,所以可以用来当作flag位

堆的释放一般都是用free函数实现。堆释放后,会被添加到相应bins中进行管理;对于空闲的chunk,ptmalloc采用分箱式内存管理方式,根据空闲chunk的大小和处于的状态将其放在四个不同的bin中,这四个空闲chunk的容器包括fast bin,unsorted bin,small bin 和 large bin

glibc malloc分配了若干个bins,为了方便查找,glibc提供了两个数组:fastbinY和bins

Bins,英文解释为垃圾桶,在这里就是存放free的chunk

image-20210130091601767

采用链表管理

image-20210130091657766

image-20210130092640011

执行完四个malloc后

image-20210130092906695

一个独有的特点:

fastbin无论在使用中还是free后,它的inuse位都是置1的

运行完第一个free后

image-20210130093422536

我这里出现了tcachebins,按理说应该是fastbins,查资料

tcache 是glibc2.26之后引进的一种新机制,类似于fastbin一样的东西,每条链上最多可以有7个chunk,free的时候当tcache满了才放入fastbin,unsortbin中,当malloc的时候,优先去tcache找

我们先从glibc2.23开始学习,所以用patchelf更换成2.23,gdb再次调试

image-20210130105947697

好,这样就可以看到fastbins中已经有了一个chunk的指针,然后我们再free一个chunk

image-20210130111213122

可以看到fastbins链表的第一个chunk为新free的chunk

image-20210130111314900

可以看到第二个chunk的fd指针变为了第一个chunk的地址

依次运行完四个free后,情况也是一样image-20210130111448020

image-20210130111630656

fastbins主要是用于提高小内存的分配效率,默认情况下,对于SIZE_SZ为4B的平台,小于64B的chunk分配请求,对于SIZE_SZ为128B的chunk分配请求,首先会查找fastbins中是否有所需大小的chunk存在(精确匹配),如果存在,就直接返回。(glibc2.23)

fastbins采用单链表管理。其他bins采用双链表

而对于大小超出fastbins范围的chunk,会先到unsortedbin中。

分配时,如果在unsorted bin中没有合适的chunk,就会把unsorted bin 中所有的chunk分别加入到所属的bin中,然后再在bin中分配合适的chunk。

下面进行验证

image-20210130121219577

我们把第一个chunk改为0x110大小,再看第一次free后的结果

image-20210130113958212

可以看到出现在了unsortedbin中,符合验证。

再看再次malloc(0x110)之后的结果

image-20210130121303175

可以看到已经被分配出去了

void *ptr=malloc(0x10);

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-6-18 23:46 被77pray编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2021-4-9 12:45
0
雪    币: 4168
活跃值: (15932)
能力值: ( LV9,RANK:710 )
在线值:
发帖
回帖
粉丝
3
支持!
2021-4-29 14:20
0
雪    币: 243
活跃值: (2547)
能力值: ( LV7,RANK:115 )
在线值:
发帖
回帖
粉丝
4
好耶
2021-5-13 17:34
0
游客
登录 | 注册 方可回帖
返回
//