실습 환경 : Ubuntu 16.04

실습 코드

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char* a=(char*)malloc(0x10);
    char* b=(char*)malloc(0x20); 
    char* b2=(char*)malloc(0x25);
    char* c=(char*)malloc(0x30);
    char* d=(char*)malloc(0x40);
    char* d2=(char*)malloc(0x45);
    char* e=(char*)malloc(0x50);
    char* f=(char*)malloc(0x60);
    char* g=(char*)malloc(0x70);

    free(a);
    free(b);
    free(b2);
    free(c);
    free(d);
    free(d2);
    free(e);
    free(f);
    free(g);    

    return 0;
}

총 10번의 malloc 호출을 하고 전부 다 free를 하는 단순한 코드입니다. fast bin이 관리하는 0x20 ~ 0x80 사이즈를 확인하기 위해 사이즈별로 동적할당을 진행했습니다. 또한 단일연결 리스트로 구성되는 걸 확인하기 위해 b2와 d2를 추가적으로 삽입했습니다.

맨 마지막 free(h)가 진행되기 직전 메모리 상태를 확인해보겠습니다.

Untitled

Untitled

그 이유는 아래와 같습니다.

현재 fastbin에 아무것도 없는 상태에서, 만약 0x20사이즈의 청크가 사용중이라고 해보자. 그렇다면 mem 영역에 사용자가 입력한 데이터가 들어가 있을 것이다. 0x20사이즈 a청크가 free되면 fastbin[0]에 들어가게 될텐데, 여기서 fd가 0으로 초기화 되지 않는다면, fastbin[0]→a청크→a청크's 데이터 이렇게 리스트가 연결되어 다음에 동일한 사이즈인 0x20이 요청들어왔을때 청크를 반환하는 것이 아닌, a청크's 데이터값을 반환하려고 할것이다.

fastbins은 단일 연결리스트로 fd에 들어가있는 값을 보고 LIFO를 진행하기 때문입니다. 아래의 그림을 보면 쉽게 이해가 될 것입니다(그림에 표현된 값들은 상관없는 값입니다).

image.gif

따라서 처음 free된 청크들의 fd를 0으로 만드는 것입니다. 어쨋든 이러한 이유로 코드에서 a, b, c, d, e, f, g 청크들의 fd 부분을 0으로 채워집니다. 직접 확인해보겠습니다.