heap
chunk结构
chunk是堆管理中内存分配的基本单元
linux的malloc具体实现在glibc中,chunk头部信息结构体如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
struct malloc_chunk {
// 前一个chunk的大小,当前一个chunk释放时堆管理器可以通过这个字段访问并合并前一个空闲块,是内存相邻的
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */
// 当前chunk总大小
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
// 下一个空闲chunk,是链表相邻的
struct malloc_chunk* fd; /* double links -- used only if free. */
// 上一个空闲chunk
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
// 指向大小略大于当前chunk的下一个空闲chunk
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
// 指向大小略小于当前chunk的上一个空闲chunk
struct malloc_chunk* bk_nextsize;
};
|
- INTERNAL_SIZE_T本质上就是unsigned int
- fd和bk通常用于管理空闲chunk链表,这使得内存管理器可以快速找到和操作空闲内存块
- fd_nextsize和bk_nextsize字段用于优化大块内存的管理,通过按大小排序的链表提高查找效率
另外在glibc的堆实现中mchunk_size不仅包含chunk的大小,还包含三个标志位
三个标志位用来表示存储标志信息,为什么会有这三个标志位?
以16字节对齐为例,在内存对齐的背景下chunk的最低四位为0000,从右往左数第一、二、三位就是三个标志位即AMP
获取实际chunk大小只需要屏蔽最低三位
1
2
3
4
5
6
7
|
#define PREV_INUSE 0x1 // P
#define IS_MMAPPED 0x2 // M
#define NON_MAIN_ARENA 0x4 // A
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
// 获取实际大小
size_t actual_size = mchunk_size & ~SIZE_BITS;
|

没有被free的chunk

free&bins
bins是一种用于管理和组织chunk的数据结构,当chunk被free后会放入合适的bins中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Fastbins */ // typedef struct malloc_chunk* mchunkptr;
mfastbinptr fastbinsY[NFASTBINS]; // 指针数组,指向不同大小的fastbins链表
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top; // 指向堆的最顶端
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder; // 指向最近一次小内存请求剩余的空间,用于减少碎片化
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2]; // 指向普通bins
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next; // 指向下一个malloc_state
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
|
bins的分类有四种,分别是fastbins
、unstored bin
、small bins
、large bins
-
fastbinsY[NFASTBINS] 单向链表
这个数组每一个元素都是指向链表头的指针,每个指针指向的都是fastbins,fastbins用于管理小且固定大小的chunk
1
2
3
|
fastbinsY[0]: -> [16字节块1] -> [16字节块2] -> ...
fastbinsY[1]: -> [32字节块1] -> [32字节块2] -> ...
...
|
-
bins[NBINS * 2 - 2] 双向链表
存储1个unstored bin头指针、62个small bins头指针、63个large bins头指针
只有large bins
被free后会有fd_nextsize
和bk_nextsize
,其余的bin只有fd
和bk
,这是因为large bins
有排序的需求
malloc和free的实现原理解析 - JackTang’s Blog (jacktang816.github.io)
内存分配
现在的linux系统的堆管理器通常是ptmalloc
,这是基于早期的dlmalloc
改进而来,在此基础上增加了多线程支持
堆分配内存会涉及到多个系统调用


【CTF】GLibc堆利用入门-机制介绍_哔哩哔哩_ bilibili