// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c/* Take a chunk off a bin list. */staticvoidunlink_chunk (mstate av, mchunkptr p){if (chunksize (p)!=prev_size (next_chunk (p)))malloc_printerr ("corrupted size vs. prev_size");mchunkptr fd =p->fd;mchunkptr bk =p->bk;if (__builtin_expect (fd->bk != p ||bk->fd != p,0))malloc_printerr ("corrupted double-linked list");fd->bk = bk;bk->fd = fd;if (!in_smallbin_range (chunksize_nomask (p))&&p->fd_nextsize !=NULL){if (p->fd_nextsize->bk_nextsize != p||p->bk_nextsize->fd_nextsize != p)malloc_printerr ("corrupted double-linked list (not small)");// Added: If the FD is not in the nextsize listif (fd->fd_nextsize ==NULL){if (p->fd_nextsize == p)fd->fd_nextsize =fd->bk_nextsize = fd;else// Link the nexsize list in when removing the new chunk{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;}}}
图形解释
查看这个关于 unlink 过程的精彩图形解释:
安全检查
检查块的指示大小是否与下一个块中指示的 prev_size 相同
还要检查 P->fd->bk == P 和 P->bk->fw == P
如果块不是小块,检查 P->fd_nextsize->bk_nextsize == P 和 P->bk_nextsize->fd_nextsize == P
泄漏
未链接的块不会清理分配的地址,因此可以访问它,可能会泄漏一些有趣的地址:
Libc 泄漏:
如果 P 位于双向链表的头部,bk 将指向 libc 中的 malloc_state
如果 P 位于双向链表的末尾,fd 将指向 libc 中的 malloc_state
当双向链表仅包含一个空闲块时,P 在双向链表中,fd 和 bk 都可以泄漏 malloc_state 中的地址。