prototype & 기본 변수들
mp_ 구조체
- malloc과 관련된 여러 상수값들이 저장되어 있다.
tcache
tcache_entry & tcache_perthread_struct
-
tcache_entry
- tcache_entry는 chunk의 data가 쓰이는 영역부터 쓰이게 된다.
- next : tcache_bin의 다음 chunk의 tcache_entry를 가리킨다.
- key : 랜덤한 값으로 생성된 key를 추가로 가진다. (double free 체크하기 위함)
-
tcache_perthread_struct
- counts[] : 각 tcache_bin 마다 현재 존재하는 chunk 수가 저장되어 있다.
- entries[] : tcache_bin들의 배열이다.
tcache 구현부분
- chunk의 사이즈가 tcache bin이 담을 수 있는 크기보다 더 크다면, 그냥 if문 탈출.
- double free되었는지 체크.
- free시에 tcache_entry->key값을 미리 생성된 랜덤 값으로 바꾸게 되는데, 만약 double free가 된 경우라면 이미 tcache_entry->key 값이 랜덤 값과 같게 된다. 하지만 같다고 해서 무조건 double free는 아닌 것이, 진짜진짜 우연으로 malloc 한 후에 넣은 데이터 값이 랜덤 값과 같을 수도 있다.
- 그러므로 key값이 랜덤값과 같은 경우 (애초에 이 경우는 거의 일어나지 않음) tcache를 순회하면서 다른 chunk와 같은 주소를 가지고 있는지 (double free되지 않았는지 알아보는 확실한 방법) 확인해 보는 것이다.
- 4465 ~ 4470 : 정상적인 경우에 해당하므로 tcache_bin에 집어넣는다.
- 물론 이미 tcache_bin이 꽉 찼을 경우 (== 7)는 못 집어넣고 다음으로 넘어감.
tcache_put
- key값을 tcache_key값 (미리 만들어진 랜덤값) 으로 바꾼다.
- 그 후, e를 tcache_bin에 집어넣는다.
- 해당 bin의 count값 증가시킴.
fastbin
- 다음 chunk의 크기가 CHUNK_HDR_SZ보다 작거나 같을 때, 혹은
다음 chunk의 크기가 av->system_mem(av가 관리하고 있는 메모리의 크기)보다 크거나 같다면 fail이 true가 되어 에러가 출력된다.
- free_perturb : chunk의 data영역을 perturb_byte로 채운다.
perturb_byte가 0이 아닌경우에만 채운다.
- atomic_store_relaxed : atomic하게 av->have_fastchunks를 true로 바꿔준다.
- 일단 이 부분은 LIFO 형태인 fastbin에 새로운 chunk를 달아주는 과정이다.
- SINGLE_THREAD_P인 경우 어차피 data race가 발생하지 않으므로 그냥 바꿔주면 된다.
- 그렇지 않은 경우, data race를 피해야 함.
-> CAS(compare and swap) atomic 함수를 이용해서 해결한다.
- catomic_compare_and_exchange_val_rel : CAS함수에 해당한다.
- fb가 가리키는 값이 old2와 같으면 그 값을 p로 바꾼다.
- 리턴값은 기존에 fb가 가리키고 있던 값이다.
- 그러므로 기존 값이 old2와 같을 때에만 old값이 old2로 바뀌어서 while문을 탈출하게 된다.
- 마지막 부분은 old와 현재 chunk의 크기가 다른 경우 에러를 출력하는 부분이다. (얘는 사실 왜 있는지 모르겠음. memory corruption때문인가)
unsorted & small & large
error handling
- 여기는 에러 처리를 담당하는 부분이다.
- chunk가 top에 해당한다면 감지.
- nextchunk가 arena가 담당하는 영역을 벗어나도 감지. (top 메모리를 벗어났을 경우)
- 현재 chunk의 inuse bit이 꺼졌을 경우 감지.
- nextsize가 올바르지 않으면 감지.
- 그 후에 free_perturb를 호출한다.
unlink_chunk - 나중에... large bin까지 하고 나서 정리합시다
- 메모리가 corrupt되지 않았는지 수시로 확인함.
- doubly-linked list의 연결을 끊어준다.
- 이후에는 largebin에 있는 경우에 해당함. (smallbin_range를 벗어나면서 fd_nextsize != NULL이 아닌 경우)
consolidate backward
- 먼저 이전 chunk가 사용중이지 않은지 확인.
- size에 consolidate 이후의 크기를 저장한다.
- 만약 prev_size와 prev_chunk의 size값이 일치하지 않는다면 에러처리
- unlink한다.
consolidate forward
- 다음 chunk가 top이 아닐 때에만 일어남.
- nextchunk의 inuse bit가 0인 경우에만 unlink를 하고, size값에 추가해준다.
- nextchunk의 inuse bit가 1인 경우에는 다음 chunk를 병합할 수는 없으므로 inuse_bit을 0으로 만들어 준다.
unsorted_bin
- unsorted bin에 넣어주는 과정.
- 특히 large_bin의 크기에 해당한다면 fd_nextsize, bk_nextsize를 NULL로 초기화한다.
- nextchunk의 prev_size, 현재 chunk의 size값을 업데이트한다.
- 만약 nextchunk == av->top이라면, 해당 chunk는 unsorted bin에 들어가지 않고 top chunk에 병합된다.
나머지
- size가 FASTBIN_CONSOLIDATION_THRESHOLD 이상이 되면, fastbin 내부의 chunk들도 consolidation을 진행한다.
- 만약 현재 av가 main_arena인지 아닌지에 따라 여러 처리를 해 준다. (수정 예정)
- 마지막으로, mmap() 되었던 메모리일 경우, munmap을 호출해 준다.
malloc_consolidate
- fastbin을 모두 순회하며 fastbin을 NULL로 만들어 주고, 각 chunk들을 unsorted bin에 넣어준다.
- av->have_fastchunks = false; 로 바꾼다.
- 얘는 사실 _int_free 함수와 거의 비슷함.
- 그래서 나머지 코드부분은 생략함.