본문 바로가기

Heap analysis/glibc 2.23

(glibc 2.23) unlink

사실 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 초기화

처음에 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번째 상태와 동일하지만 다른 크기의 청크들도 있을 경우

(이해를 돕기 위한 그림은 아래 더보기)

더보기
조건1

 

조건2

 

조건3

 

 

 

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