美文网首页
ptmalloc | free 总体流程简述 | 无原子优化相关

ptmalloc | free 总体流程简述 | 无原子优化相关

作者: fantasy_learner | 来源:发表于2019-01-16 21:28 被阅读0次

当前流程 不考虑 开启原子优化

Public_fREe(void *mem)

  • __free_hook == null ? pass : __free_hook(mem) # 如果 __free_hook 不为 null , 调用 __free_hook
  • mem == null ? return; : mem2chunk(mem) => p; # 检测 mem 是否为 null , 如果为null , 直接return , 无影响
  • if HAVE_MMAP # 检测 HAVE_MMAP 标识符
    • chunk_is_mmaped(p) # 检测是否是 mmap 分配的
      • !mp_.no_dyn_threshold && p->size > mp_.mmap_threshold && p->size <= DEFAULT_MMAP_THRESHOLD_MAX # 检测 动态调整 mmap_threshold 是否开启 和 条件是否满足 ([mp_,mmap_threshold + 1 , DEFAULT_MMAP_THRESHOLD_MAX ])
      • mp_.mmap_threshold = chunksize (p); # 调整 分配阈值为 chunksize(p)
        • mp_.trim_threshold = 2 * mp_.mmap_threshold # 调整 收缩阈值
    • munmap_chunk(p) # 解除映射
  • ar_ptr = arena_for_chunk(p); # 根据 chunk 获取 arena 的指针
  • 对 分配区 尝试加锁
  • _int_free(ar_ptr, p); # 调用 _int_free 执行实际的释放工作
  • 对 分配去 解锁

_int_free(mstate av, mchunkptr p)

  • 检测1 : p > -size || (misaligned_chunk (p)
    • 报错标志 : free(): invalid pointer
    • 检测内容 : 指针地址是否溢出 , 指针的地址 是否对齐
    • 相关参数 :
      • size = chunksize(p)
  • 检测2 : size < MINSIZE
    • 报错标志 : free(): invalid size
    • 检测内容 : chunk size 是否 大于 MINSIZE
    • 相关参数:
      • size = chunksize(p)
  • size <= get_max_fast () # fastbin chunk
    • if TRIM_FASTBINS # 检测 TRIM_FASTBINS 标识符
      • 作用 : 如果该标识符为 True , 靠近 top chunk 的 fastbin 不会进入该逻辑进行处理
    • 检测 1: chunk_at_offset (p, size)->size <= 2 * SIZE_SZ || chunksize (chunk_at_offset (p, size)) >= av->system_mem
      • 报错标志: free(): invalid next size (fast)
      • 检测内容 : 下一个 chunk 的 size 是否 <= MINSIZE 或者 大于 分配内存总量
    • 检测 2 : *fb == p
      • 报错标志 : double free or corruption (fasttop)
      • 检测内容 : 对应大小的 fastbin 链表表头 的 chunk 和 即将要 free 的 chunk 是否相同 , 即 double free # 这里是 fastbin attack 中 double free 的 利用原理
      • 相关参数 :
        • unsigned int idx = fastbin_index(size)
        • fb = &fastbin (av, idx)
    • 检测 3 : fb != NULL && fastbin_index(chunksize(fb)) != idx
      • 报错标志 : invalid fastbin entry (free)
      • 检测内容 : 检测 对应fastbin 的 idx 和 p 的 idx 是否相同
      • 相关参数 :
        • unsigned int idx = fastbin_index(size)
        • fb = &fastbin (av, idx)
    • 加入 链表表头
      • fd | *next
      • LIFO | 后进先出
  • if chunk_is_mmapped(p) : | mmap 分配的 chunk # 原为 else 的 处理 ,在最下方
    - munmap_chunk (p); | 使用 munmap_chunk 解除映射
  • if !chunk_is_mmapped(p) : # 不是 mmap 分配的 chunk # 此处 是原代码的判断 , 为了便于查看 , 将 mmap 分配内存的处理调整到 上方
    • 检测 1 : p == av->top
      • 报错标志 : double free or corruption (top)
      • 检测内容 : p 是否是 top chunk
    • 检测 2 : next_chunk >= av->top + chunksize(av->top)
      • 报错标志 : double free or corruption (out)
      • 检测内容 : next_chunk 是否超过了 main_arena 的 范围 , 地址溢出?
      • 相关参数 :
        • nextchunk = chunk_at_offset(p , size)
    • 检测 3 : !prev_inuse(next_chunk)
      • 报错标志 : double free or corruption (!prev)
      • 检测内容 : 检测当前 chunk 是否正在使用
      • 相关参数 :
        • nextchunk = chunk_at_offset(p , size)
    • 检测 4 : nextchunk->size <= 2 * SIZE_SZ || nextsize >= av->system_mem
      • 报错标志 : free(): invalid next size (normal)
      • 检测内容 : 检测下一个 chunk 的大小是否在合理范围内 [ 2 * SIZE_SZ : av->system_mem]
      • 相关参数 :
        • nextsize = chunksize(nextchunk)
        • nextchunk = chunk_at_offset(p , size)
    • consolidate forward | 前向合并
      • 前置条件 : !prev_inuse(p) # 检测 前一个 chunk 是否在使用中
      • 操作过程 :
        • prevsize = p->prev_size
        • size += prevsize # 增加 size 的 长度
        • p = chunk_at_offset(p , - prevsize) # 设置 p 的 新位置
        • unlink(p , bck , fwd) # unlink 操作 , 将前一个 chunk 从空闲 chunk 链表中移除
      • consolidate backward | 后向合并
      • 前置条件 : nextchunk != av->top && !nextinuse # 检测 下一个 chunk 是不是 topchunk 并且下一个 chunk 空闲
        • 相关参数 :
          • nextchunk = chunk_at_offset(p , size)
          • nextinuse = inuse_bit_at_offset(nextchunk, nextsize) | 获取 nextchunk 的使用状态
        • 操作过程:
        • unlink(nextchunk, bck, fwd) | unlink 下一个chunk
        • size += nextsize
      • else :# 下一个 chunk 不空闲
        • clear_inuse_bit_at_offset(nextchunk, 0) # 设置当前 chunk 的使用状态为 空闲
    • if nextchunk != av->top : # 下一个 chunk 不是 top chunk 时 , 放入 unsorted bin
      • 检测 1 : fwd->bk != bck
        • 报错标志 : free(): corrupted unsorted chunks
        • 检测内容 : 检测 unsorted_bin 的第一个 chunk 的bk 是否指向 &unsorted_bin_list
        • 相关参数 :
          • bck = unsorted_chunks(av)
          • fwd = bck->fd
      • 放入链表尾部:
        • 操作 :
            1. p->fd = fwd; p->bk = bck; | unsorted bin attack 的原理
            1. bck->fd = p;fwd->bk = p;
              • if !in_smallbin_range(size) | large bin
                • p->fd_nextsize = NULL; p->bk_nextsize = NULL
            1. set_head(p, size | PREV_INUSE); # 设置 p 的 size 域
            1. set_foot(p, size) # 设置 p 的 next_chunk 的 prev_size
    • else: # 下一个 chunk 是 top chnk
      • size += nextsize | size 加上 topchunk的size
      • av-top = p | 将 top chunk 的地址 设置为 p
    • if (size) >= FASTBIN_CONSOLIDATION_THRESHOLD | 如果合并后 size > fastbin 整合的阈值
      • if hava_fastchunks(av) | 如果 有 fastbin chunk
      • malloc_consolidate(av) | 对fastbin chunks 进行一次整合 , 整合 fastbin chunk 到 unsorted bin 中
        • if (av == &main_arena) | 判断 当前 arena 是不是主分配区
          • if ( chunksize(av->top) > mp_.trim_threshold) | 判断 top chunk 的大小是否超过了heap 的收缩阈值
          • sYSTRIm(mp_.top_pad , av) | 调用 sYSTRIm 进行收缩
        • else : | 非主分配区
        • heap_info *heap = heap_for_ptr(top(av));
        • assert(heap->ar_ptr == av);
        • heap_trim(heap, mp_.top_pad); | 尝试用 heap_trim 收缩 子分配区

相关文章

网友评论

      本文标题:ptmalloc | free 总体流程简述 | 无原子优化相关

      本文链接:https://www.haomeiwen.com/subject/nbrvdqtx.html