堆结构记录

fast bin

LIFO 最近释放的chunk会被更早分配,当用户需要的 chunk 的大小小于 fastbin 的最大大小时, ptmalloc 会首先判断 fastbin 中相应的 bin 中是否有对应大小的空闲块,有的话分配,否则ptmalloc 进行下一步操作。fast bin chunk大小最大64字节,但是其可以支持的 chunk 的数据空间(出去pre_size、chunk_size)最大为 80 字节。除此之外, fastbin 最多可以支持的 bin 的个数为 10 个,从数据空间为 8 字节开始一直到 80 字节。
64位:在0x20~0x80之间
32位:在0x10~0x40之间(包含区间边界)
p位均为1,防止与其他chunk合并以加快小内存分配

需要特别注意的是,fastbin 范围的 chunk 的 inuse 始终被置为 1。因此它们不会和其它被释放的 chunk 合并。

但是当释放的 chunk 与该 chunk 相邻的空闲 chunk 合并后的大小大于 FASTBIN_CONSOLIDATION_THRESHOLD 时,内存碎片可能比较多了,我们就需要把 fast bins 中的 chunk 都进行合并,以减少内存碎片对系统的影响。

small bin(bin2-bin63)

small bins 中每个 chunk 的大小与其所在的 bin 的 index 的关系为:chunk_size = 2 * SIZE_SZ *index,具体如下:

下标SIZE_SZ=4(32 位)SIZE_SZ=8(64 位)
21632
32448
43264
54080
x24x28x
635041008

small bins 中一共有 62 个循环双向链表,每个链表中存储的 chunk 大小都一致。采用FIFO
主要用于保存在0x10~0x400(x86,对x64是0x20~0x800)区间的堆块,同一条链表中堆块的大小相同,如x86下bin2对应于0x10,bin3对应于0x18……

unsorted bin(bin1)

unsorted bin 可以视为空闲 chunk 回归其所属 bin 之前的缓冲区,unsorted bin 中的空闲 chunk 处于乱序状态,主要有两个来源:

  • 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。
  • 释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。 此外,Unsorted Bin在使用的过程中,采用的遍历顺序是 FIFO 。

主要用于存放刚释放的堆块以及大堆块,分配后剩余的堆块,大小没有限制.

large bin(bin64-bin126)

主要用来存放大小大于0x400(x86,对x64是0x800)的堆块,同一条链表中堆块的大小不一定相同,在一定范围内,按照从小到大的顺序进行排列。这 63 个 bin 被分成了 6 组,每组 bin 中的 chunk 大小之间的公差一致.

数量公差
13264B
216512B
384096B
4432768B
52262144B
61不限制

malloc过程

1)检查size_real是否符合fast bin的大小,若是则查看fast
bin中对应size_real的那条链表中是否存在堆块,若是则分配返回, 否则进入第2步。 2)检查size_real是否符合small
bin的大小,若是则查看small bin中对应size_real的那条链表中是否存在堆块,若是则分配返回, 否则进入第3步。
3)检查size_real是否符合large bin的大小,若是则调用 malloc_consolidate函数对fast
bin中所有的堆块进行合并,其过程 为将fast bin中的堆块取出,清除下一块的p标志位并进行堆块合并, 将最终的堆块放入unsorted
bin。然后在small bin和large bin中找 到适合size_real大小的块。若找到则分配,并将多余的部分放入
unsorted bin,否则进入第4步。 4)检查top chunk的大小是否符合size_real的大小,若是则分配
前面一部分,并重新设置top chunk,否则调用malloc_consolidate函 数对fast
bin中的所有堆块进行合并,若依然不够,则借助系统调用 来开辟新空间进行分配,若还是无法满足,则在最后返回失败。

free 过程

1)释放(free)时首先会检查地址是否对齐,并根据size找到下
一块的位置,检查其p标志位是否置为1。
2)检查释放块的size是否符合fast bin的大小区间,若是则直接
放入fast bin,并保持下一堆块中的p标志位为1不变(这样可以避免
在前后块释放时进行堆块合并,以方便快速分配小内存),否则进入
第3步。
3)若本堆块size域中的p标志位为0(前一堆块处于释放状态),
则利用本块的pre_size找到前一堆块的开头,将其从bin链表中摘除
(unlink),并合并这两个块,得到新的释放块。
4)根据size找到下一堆块,如果是top chunk,则直接合并到top
chunk中去,直接返回。否则检查后一堆块是否处于释放状态(通过检
查下一堆块的下一堆块的p标志位是否为0)。将其从bin链表中摘除
(unlink),并合并这两块,得到新的释放块。
5)将上述合并得到的最终堆块放入unsorted bin中去。
这里有以下几个值得注意的点:
1)合并时无论向前向后都只合并相邻的堆块,不再往更前或者更
后继续合并。
2)释放检查时,p标志位很重要,大小属于fast bin的堆块在释
放时不进行合并,会直接被放进fast bin中。在malloc_consolidate
时会清除fast bin中所对应的堆块下一块的p标志位,方便对其进行合
并。

tcache

libc2.26之后的新机制,类似于fastbin,每条链最多有7个chunk,分配前先分配tcache,free后先放入tcache,满了之后才会放入其所属链表。

1)tcache的管理是单链表,采用LIFO原则。
2)tcache的管理结构存在于堆中,默认有64个entry,每个entry
最多存放7个chunk。
3)tcache的next指针指向chunk的数据区(与fast bin不同,
fast bin指向chunk头)。
4)tcache的某个entry被占满以后,符合该entry大小的chunk被
free后的规则和原有机制相同(未使用tcache时)。
未完待续!


详见 Tcache Attack

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值