堆概述及其例题
堆概念
在stdlib的头文件中存在malloc函数和free函数
两个系统调用
brk()
brk()是通过增加break location 来获取内存的,开始heap区域的起点start_brk和终点brk是指向同一个位置的,
ASLR关闭时,这两者都会指向data/bss 段的末端,就是下面的end_data
ASLR开启时,这两者会在data/bss段的末端加上一段随机的的brk偏移
溢出方式:堆是向上面溢出的
怎么一出到下面的空间:在32位的程序中通过整数溢出,超过这段空间时会从下面进行溢出
怎么增大空间的:第一次申请空间的时候就是把brk结束的标识符往上面进行移动
当brk方式增大的空间超过了一定的地方就变成了mmap()溢出了
mmap()
用于创建私有的匿名映射段,主要是为了分配一块新的内存,并且这块内存只用调用mmap()的进程才可以使用,所以时私有的。与之相反的操作时munmap(),删除一段内存区域上面的映射
malloc 会使用 mmap()来创建独立的匿名映射段。匿名映射的目的主要是可以申请以 0 填充的内存,并且这块内存仅被调用进程所使用
多线程和Arena
在原来的 dlmalloc 实现中,当两个线程同时要申请内存时,只有一个线程可以进入临界区申请内存,而另外一个线程则必须等待直到临界区中不再有线程。这是因为所有的线程共享一个堆。在 glibc 的 ptmalloc 实现中,比较好的一点就是支持了多线程的快速访问。在新的实现中,所有的线程共享多个堆
这说明虽然程序可能只是向操作系统申请很小的内存,但是为了方便,操作系统会把很大的内存分配给程序。这样的话,就避免了多次内核态与用户态的切换,提高了程序的效率。我们称这一块连续的内存区域为 arena。
此外,我们称由主线程申请的内存为 main_arena。后续的申请的内存会一直从这个 arena 中获取,直到空间不足。当 arena 空间不足时,它可以通过增加 brk 的方式来增加堆的空间。类似地,arena 也可以通过减小 brk 来缩小自己的空间
1 | sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread |
在主线程释放内存后,我们从下面的输出可以看出,其对应的 arena 并没有进行回收,而是交由 glibc 来进行管理。当后面程序再次申请内存时,在 glibc 中管理的内存充足的情况下,glibc 就会根据堆分配的算法来给程序分配相应的内存
1 | sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread |
就是意味着你虽然在程序里面加入了释放这段堆空间的指令,但是实际上,这段空间没有直接消失,而是交给glibc了,等待下一个的分配
堆的相关结构
malloc_chunk
chunk
就是最小的
在程序的执行过程中,我们称由 malloc 申请的内存为 chunk 。这块内存在 ptmalloc 内部用 malloc_chunk 结构体来表示。当程序申请的 chunk 被 free 后,会被加入到相应的空闲管理列表中
并且chunk的结构都是一样的,在内存下面都是一样,只是状态不同会用不同的标识符进行标记
当一个 chunk 处于已分配状态时,它的物理相邻的下一个 chunk 的 prev_size 字段必然是无效的,故而这个字段就可以被当前这个 chunk 使用
未完待续…