selph
selph
发布于 2024-01-12 / 35 阅读
0
0

[libc 2.35 源码学习] 断链函数 unlink_chunk

/* Take a chunk off a bin list.  */
static void
unlink_chunk(mstate av, mchunkptr p)
{
    // 安全检查:如果当前chunk的大小不等于next chunk的prev_size,说明被篡改了数据,报错
    if (chunksize(p) != prev_size(next_chunk(p)))
        malloc_printerr("corrupted size vs. prev_size");

    mchunkptr fd = p->fd;
    mchunkptr bk = p->bk;

    // 安全检查:如果当前chunk的fd的bk不等于当前chunk,或者bk的fd不等于当前chunk,说明双向链表链接出错,报错
    if (__builtin_expect(fd->bk != p || bk->fd != p, 0))
        malloc_printerr("corrupted double-linked list");

    // 断链操作
    fd->bk = bk;
    bk->fd = fd;

    // 如果是large chunk
    // 如果不是smallbin,且fd_nextsize不为空,说明是large chunk
    if (!in_smallbin_range(chunksize_nomask(p)) && p->fd_nextsize != NULL)
    {
        // 安全检查:largebin的第二条双链完整性检查
        // 安全检查:如果fd_nextsize的bk_nextsize不等于p,或者bk_nextsize的fd_nextsize不等于p,说明双向链表链接出错,报错
        if (p->fd_nextsize->bk_nextsize != p || p->bk_nextsize->fd_nextsize != p)
            malloc_printerr("corrupted double-linked list (not small)");

        // 如果存在其他大小范围的large chunk
        if (fd->fd_nextsize == NULL)
        {
            // 如果其他大小的large chunk是自己,就设置为自己
            if (p->fd_nextsize == p)
                fd->fd_nextsize = fd->bk_nextsize = fd;
            else
            {
                // nextsize链表断链
                fd->fd_nextsize = p->fd_nextsize;
                fd->bk_nextsize = p->bk_nextsize;
                p->fd_nextsize->bk_nextsize = fd;
                p->bk_nextsize->fd_nextsize = fd;
            }
        }
        else
        {
            // 正常的断链
            p->fd_nextsize->bk_nextsize = p->bk_nextsize;
            p->bk_nextsize->fd_nextsize = p->fd_nextsize;
        }
    }
}

双链表断链流程:

  1. 安全检查:下一个chunk的prev_size和当前size是否匹配,不匹配就报错
  2. 安全检查:链表完整性检查,**p->fd->bk****p->bk->fd**是否都指向**p**,不是就报错
  3. 检查通过之后,fdbk断链
  4. 如果是large chunk,则存在另一条双链表
  5. 安全检查:对另一个双链表进行链表完整性检查
  6. 检查通过之后,fd_nextsizebk_nextsize断链

评论