사실 unlink에 대해 매우 잘 정리되어 있는 블로그 글이 많다
그냥 공부한 것을 다시 복기하고 제대로 익히기 위해 정리하려한다
전체 코드는 아래 더보기
/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) { \
FD = P->fd; \
BK = P->bk; \
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
malloc_printerr (check_action, "corrupted double-linked list", P, AV); \
else { \
FD->bk = BK; \
BK->fd = FD; \
if (!in_smallbin_range (P->size) \
&& __builtin_expect (P->fd_nextsize != NULL, 0)) { \
if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) \
|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) \
malloc_printerr (check_action, \
"corrupted double-linked list (not small)", \
P, AV); \
if (FD->fd_nextsize == NULL) { \
if (P->fd_nextsize == P) \
FD->fd_nextsize = FD->bk_nextsize = FD; \
else { \
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; \
} \
} \
} \
}
인자
#define unlink(AV, P, BK, FD)
unlink 매크로는 freed 청크가 병합이 이루어질때 연결 리스트에서 제거될때 fd와 bk를 정리해주는 작업을 한다
해당 매크로에 들어오는 인자들은 아래와 같다
- AV : 현재 아레나
- P : unlink할 청크 주소
- BK : P->bk
- FD : P->fd
initial check
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
malloc_printerr (check_action, "corrupted double-linked list", P, AV);
가장 먼저 해제하려는 청크 P가 올바른 위치에 있는지에 대한 검사를 한다
만약 p->fd주소의 bk가 p가 아니거나 p->bk의 fd가 p가 아니면 비정상적으로 종료된다
small bin unlink
else { \
FD->bk = BK; \
BK->fd = FD; \
...
}
P와 인접한 P->fd와 P->bk에 대한 검증에서 문제가 없으면 else에 있는 코드가 수행된다
가장 먼저 FD->bk에 BK를 저장하고 BK->fd에 FD를 저장한다
처음에 FD와 BK에 p의 fd와 bk를 저장한 것을 생각해보면 위와 같을 것이다
이후 검증을한 뒤 통과하게 되면 else문에서 FD->bk에 BK를 저장하고 BK->fd에 FD를 저장하게 되면서 청크 p가 해제된다
large bin unlink
청크가 P가 large bin이면 FD, BK를 추가로 fd_nextsize와 bk_nextsize도 unlink를 하는 작업이 필요하다
수행되는 코드는 아래 더보기
if (!in_smallbin_range (P->size) \
&& __builtin_expect (P->fd_nextsize != NULL, 0)) { \
if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) \
|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) \
malloc_printerr (check_action, \
"corrupted double-linked list (not small)", \
P, AV); \
if (FD->fd_nextsize == NULL) { \
if (P->fd_nextsize == P) \
FD->fd_nextsize = FD->bk_nextsize = FD; \
else { \
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하게될 청크는 아래중 1개일 것이다
- p가 다른 크기의 청크들과 연결되어 있을 경우
- p가 bin의 fd에 있고 bin에 같은 크기의 청크들만 있을 경우
- 2번째 상태와 동일하지만 다른 크기의 청크들도 있을 경우
(이해를 돕기 위한 그림은 아래 더보기)



check large bin
if (!in_smallbin_range (P->size) \
&& __builtin_expect (P->fd_nextsize != NULL, 0)) { \
...
}
청크 p 크기가 large bin에 해당하고 같은 크기 청크에 연결된 청크인지 검사한다
(같은 크기 청크에 연결된 청크는 fd, bk으로만 연결되기 때문에 fd_nextsize와 bk_nextsize를 unlink 할 필요가 없다)
if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) \
|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) \
malloc_printerr (check_action, \
"corrupted double-linked list (not small)", \
P, AV); \
위에서 p 청크와 인접한 fd, bk주소의 fd, bk가 p 청크의 포인터인지 확인한 것과 동일한 검사를 fd_nextsize와 bk_nextsize를 가지고 수행한다
unlink
if (FD->fd_nextsize == NULL) { \
if (P->fd_nextsize == P) \
FD->fd_nextsize = FD->bk_nextsize = FD; \
else { \
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가 되는 청크는 2가지가 있다
fd, bk로만 연결된 freed chunk와 fd_nextsize, bk_nextsize도 연결된 청크가 있다 (large bin 글에서 설명)
else { \
P->fd_nextsize->bk_nextsize = P->bk_nextsize; \
P->bk_nextsize->fd_nextsize = P->fd_nextsize; \
}
위에서 1번째 조건에 해당할때 위와 같이 unlink를 한다
if (FD->fd_nextsize == NULL) { \
if (P->fd_nextsize == P) \
FD->fd_nextsize = FD->bk_nextsize = FD; \
else { \
FD->fd_nextsize = P->fd_nextsize; \
FD->bk_nextsize = P->bk_nextsize; \
P->fd_nextsize->bk_nextsize = FD; \
P->bk_nextsize->fd_nextsize = FD; \
} \
}
이후에 2번째 조건에 부합하는지 검사한다
2번째 조건에 부합할 경우 if문 내에서 FD의 fd_nextsize, bk_nextsize에 FD값을 저장한다
3번째 조건에 부합할 경우 else문에서 p->fd_nextsize와 p->bk_nextsize와 연결한다
'Heap analysis > glibc 2.23' 카테고리의 다른 글
(glibc 2.23) malloc (0) | 2022.04.25 |
---|---|
(glibc 2.23) _int_free (0) | 2022.04.25 |
(glibc 2.23)check_malloced_chunk (0) | 2022.03.30 |
(glibc 2.23) free (0) | 2022.03.23 |
(glibc 2.23) do_check_free_chunk (0) | 2022.03.22 |