堆结构(Heap Structure)

目录

0x01.堆的定义

0x02.堆管理器的主要工作

向操作系统申请内存

管理用户所释放的内存

0x03.堆的基本操作

malloc

在 glibc 的malloc.h中,malloc 的说明:

free

在 glibc 的 malloc.h 中,free 的说明:

0x04.内存分配背后的系统调用

(s)brk

mmap

0x05.多线程支持


0x01.堆的定义

  • 在程序运行过程中,堆可以提供动态分配的内存,允许程序申请大小未知的内存。
  • 堆其实就是程序虚拟地址空间的一块连续的线性区域,它由低地址向高地址方向增长
  • 一般称管理堆的那部分程序为堆管理器。
  • 堆管理器处于用户程序与内核中间。
  • 目前 Linux 标准发行版中使用的堆分配器是 glibc 中的堆分配器:ptmalloc2。ptmalloc2 主要是通过 malloc/free 函数来分配和释放内存块。
  • 只有当真正访问一个地址的时候,系统才会建立虚拟页面与物理页面的映射关系
  • 虽然操作系统已经给程序分配了很大的一块内存,但是这块内存其实只是虚拟内存。只有当用户使用到相应的内存时,系统才会真正分配物理页面给用户使用。

0x02.堆管理器的主要工作

向操作系统申请内存

  • 响应用户的申请内存请求,向操作系统申请内存,然后将其返回给用户程序。同时,为了保持内存管理的高效性,内核一般都会预先分配很大的一块连续的内存,然后让堆管理器通过某种算法管理这块内存。只有当出现了堆空间不足的情况,堆管理器才会再次与操作系统进行交互。

管理用户所释放的内存

  • 一般来说,用户释放的内存并不是直接返还给操作系统的,而是由堆管理器进行管理。这些释放的内存可以来响应用户新申请的内存的请求。

0x03.堆的基本操作

malloc

在 glibc 的malloc.h中,malloc 的说明:

/*
  malloc(size_t n)
  Returns a pointer to a newly allocated chunk of at least n bytes, or null
  if no space is available. Additionally, on failure, errno is
  set to ENOMEM on ANSI C systems.
  If n is zero, malloc returns a minumum-sized chunk. (The minimum
  size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
  systems.)  On most systems, size_t is an unsigned type, so calls
  with negative arguments are interpreted as requests for huge amounts
  of space, which will often fail. The maximum supported value of n
  differs across systems, but is in all cases less than the maximum
  representable value of a size_t.
*/

翻译: 

malloc(size_t n)
返回指向新分配的块(至少为n字节)或空的指针(如果没有可用的空间)。
此外,如果失败,errno是在ANSI C系统上设置为ENOMEM。
如果n为零,malloc返回最小大小的块。
(最小值在大多数32位系统上大小是16字节,在64位系统上是24或32字节。)
当 n 为负数时,由于在大多数系统上,size_t 是无符号数,所以程序就会申请很大的内存空间,
但通常来说都会失败,因为系统没有那么多的内存可以分配。
n支持的最大值取决于不同的系统,但在所有情况下都小于最大值大小的可表示值(size_t)。
  • malloc 函数返回对应大小字节的内存块的指针。
  • 当 n=0 时,返回当前系统允许的堆的最小内存块。
  • 当 n 为负数时,由于在大多数系统上,size_t 是无符号数,所以程序就会申请很大的内存空间,但通常来说都会失败,因为系统没有那么多的内存可以分配。

free

在 glibc 的 malloc.h 中,free 的说明:

/*
      free(void* p)
      Releases the chunk of memory pointed to by p, that had been previously
      allocated using malloc or a related routine such as realloc.
      It has no effect if p is null. It can have arbitrary (i.e., bad!)
      effects if p has already been freed.
      Unless disabled (using mallopt), freeing very large spaces will
      when possible, automatically trigger operations that give
      back unused memory to the system, thus reducing program footprint.
    */

翻译:

free(void* p)
释放p所指的内存块(之前使用malloc或相关例程(如realloc)分配的。)  
如果p为空则无效。
当 p 已经被释放之后,再次释放会出现乱七八糟的效果。
除了被禁用 (mallopt) 的情况下,当释放很大的内存空间时,程序会将这些内存空间还给系统,以便于减小程序所使用的内存空间。   
  • free 函数会释放由 p 所指向的内存块。这个内存块有可能是通过 malloc 函数得到的,也有可能是通过相关的函数 realloc 得到的。
  • 当 p 为空指针时,函数不执行任何操作。
  • 当 p 已经被释放之后,再次释放会出现乱七八糟的效果。
  • 除了被禁用 (mallopt) 的情况下,当释放很大的内存空间时,程序会将这些内存空间还给系统,以便于减小程序所使用的内存空间。

0x04.内存分配背后的系统调用

  • 无论是 malloc 函数还是 free 函数,并不是真正与系统交互的函数。
  • 这些函数背后的系统调用主要是 (s)brk 函数以及 mmap, munmap 函数。

(s)brk

  • 对于堆的操作,操作系统提供了 brk 函数,glibc 库提供了 sbrk 函数,我们可以通过增加 brk 的大小来向操作系统申请内存。
  • 初始时,堆的起始地址 start_brk 以及堆的当前末尾 brk 指向同一地址。
  • 根据是否开启ASLR,两者的具体位置会有所不同。
  • 不开启 ASLR 保护时,start_brk 以及 brk 会指向 data/bss 段的结尾。
  • 开启 ASLR 保护时,start_brk 以及 brk 也会指向同一位置,只是这个位置是在 data/bss 段结尾后的随机偏移处。

mmap

  • malloc 会使用 mmap来创建独立的匿名映射段。
  • 匿名映射的目的主要是可以申请以0填充的内存,并且这块内存仅被调用进程所使用。

0x05.多线程支持

  • 在原来的 dlmalloc 实现中,当两个线程同时要申请内存时,只有一个线程可以进入临界区申请内存,而另外一个线程则必须等待直到临界区中不再有线程。
  • 这是因为所有的线程共享一个堆。在glibc的ptmalloc实现中,比较好的一点就是支持了多线程的快速访问。
  • 在新的实现中,所有的线程共享多个堆。

具体前往:https://wiki.x10sec.org/pwn/heap/heap_overview/#_2

发布了90 篇原创文章 · 获赞 99 · 访问量 9171

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/104648026