0%

fastbins


fast bins 的大小范围

  1. 单个 fast bin 管理的块大小
  • 每个 fast bin 对应一种固定大小的内存块,块大小按 8 字节递增(32 位系统)或 16 字节递增(64 位系统)。

  • 64 位系统示例(常见场景):

  • 最小块大小:0x20 字节(包含 16 字节的头部 0x10 + 对齐填充 0x10)。

  • 最大块大小:0x80 字节(即 fastbin_max_size = 0x80,超过此大小的块不属于 fast bins)。

  • 有效大小序列:0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80(共 7 个 fast bin)。

  • 32 位系统示例

  • 最小块大小:0x10 字节(头部 0x8 + 对齐填充 0x8)。

  • 最大块大小:0x78 字节(fastbin_max_size = 0x78)。

  • 有效大小序列:0x10, 0x18, 0x20, …, 0x78(按 8 字节递增)。

  1. 关键参数
  • fastbin_max_size:定义 fast bins 能管理的最大块大小(64 位系统默认 0x80,32 位系统默认 0x78)。
  • 块大小计算:块大小需包含头部(prev_sizesize 字段)和用户数据区,且需按 16 字节对齐(64 位)或 8 字节对齐(32 位)。

问题 1:Fastbins 的 fd 指向谁?

Fastbins 采用 LIFO(后进先出) 结构,后释放的堆块会放在链表头部,而 **fd** 指向的是先前被释放的堆块

示例:

1
2
3
ptr1 = malloc(0x10);
ptr2 = malloc(0x10);
ptr3 = malloc(0x10);

此时堆结构如下:

[ ptr1 ] [ ptr2 ] [ ptr3 ]

释放顺序:

如果我们按照 free(ptr1) -> free(ptr2) -> free(ptr3) 释放堆块,则 Fastbins 的链表结构如下:

Fastbins 结构(LIFO,头部插入):

1
2
3
4
+---------+       +---------+       +---------+
| ptr3 |-----> | ptr2 |-----> | ptr1 |-----> NULL
+---------+ +---------+ +---------+
(最近释放) (第二个释放) (最早释放)

对应的 fd 指针:

1
2
3
ptr3->fd = ptr2
ptr2->fd = ptr1
ptr1->fd = NULL

Fastbins 结构更新:

1
2
3
4
+---------+       +---------+
| ptr2 |-----> | ptr1 |-----> NULL
+---------+ +---------+
(第二个释放) (最早释放)

再申请一个 malloc(0x10)ptr2 会被分配:

1
2
3
4
+---------+
| ptr1 |-----> NULL
+---------+
(最早释放)

再申请一个 malloc(0x10)ptr1 被分配,Fastbins 变为空。

完整示意图

释放过程:

1
2
3
4
5
free(ptr1)   free(ptr2)   free(ptr3)
↓ ↓ ↓
+------+ +------+ +------+
| ptr1 | | ptr2 | | ptr3 |
+------+ +------+ +------+

Fastbins 变成:

ptr3 -> ptr2 -> ptr1 -> NULL

分配过程:

如果 malloc(0x10)

1
2
分配 ptr3:
ptr2 -> ptr1 -> NULL

malloc(0x10)

1
2
分配 ptr2:
ptr1 -> NULL

malloc(0x10)

1
2
分配 ptr1:
NULL(Fastbins 为空)

总结:

  • Fastbins 释放时,后释放的堆块会放在链表头部,而 **fd** 指向的是先前释放的堆块
  • Fastbins 申请时,总是优先分配最近释放的堆块(LIFO 规则)
// 在最后添加