zImage에서 압축 해제코드를 분석하던 중 malloc을 사용하길래 해당 함수도 같이 분석했습니다. 이 때 나온 의문점인데 스터디 내에서 해결되지 않아 질문 올립니다.
질문 1-1: 압축해제에 사용한 malloc 은 다음과 같습니다. 전역변수로 heap의 시작주소인 free_mem_ptr을 malloc_ptr에 저장해서 사용합니다. 해당 주소부터 전달받은 size만큼 영역을 할당해서 리턴해 주는데, free를 할 때 문제가 있어 보입니다.
free를 할 때 malloc_count를 이용하여 할당영역 해제를 해주는데, 부주의한 실수로 malloc할당이 하나가 남아있다면, malloc_count는 0이 아니므로, malloc_ptr은 free_mem_ptr로 초기화 되지않고 상승된 주소로 그대로 있습니다.
이 말은 malloc 할당이 하나라도 남은 상태에서 malloc을 계속해서 쓴다면, free를 해도 free가 되지 않는 경우가 될 것 같습니다. 왜 이런걸까요? include/linux/decompress/mm.h의 malloc 이 아닌 lib/inflate.c에 존재하는 malloc 또한 같은 상황입니다.
33 static void *malloc(int size)
34 {
35 void *p;
36
37 if (size < 0)
38 return NULL;
39 if (!malloc_ptr)
40 malloc_ptr = free_mem_ptr;
41
42 malloc_ptr = (malloc_ptr + 3) & ~3; /* Align */
43
44 p = (void *)malloc_ptr;
45 malloc_ptr += size;
46
47 if (free_mem_end_ptr && malloc_ptr >= free_mem_end_ptr)
48 return NULL;
49
50 malloc_count++;
51 return p;
52 }
53
54 static void free(void *where)
55 {
56 malloc_count--;
57 if (!malloc_count)
58 malloc_ptr = free_mem_ptr;
/*!
* malloc_count == 0 -> 할당된 영역이 없으면 malloc_ptr = heap_start_address
* 의문점 -> 힙 할당이 하나라도 되있는 상태에서
* 말록을 사용하면 malloc_ptr이 커지기만 해서 결국 메모리 사이즈를 벗어남
* 후기에서 질문.
*/
59 }
댓글 8
-
이동표(구름과비)
2014.07.09 08:54
-
이동표(구름과비)
2014.07.09 09:00
1023 mov r0, r41024 mov r1, sp @ malloc space above stack1025 add r2, sp, #0x10000 @ 64k max1026 mov r3, r71027 bl decompress_kernel위에서 decompress_kernel 함수를 호출할 때 3 번째 인자로 malloc (64k) 의 끝을 넘겨주고 있고...133 void134 decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,135 unsigned long free_mem_ptr_end_p,136 int arch_id)137 {138 int ret;139140 output_data = (unsigned char *)output_start;141 free_mem_ptr = free_mem_ptr_p;142 free_mem_end_ptr = free_mem_ptr_end_p;143 __machine_arch_type = arch_id;그 3 번째 인자를 free_mem_end_ptr 이라는 전역 변수에 설정해두고 있습니다.그러니까, malloc 함수에서 적어도 malloc 영역(64k)의 끝을 check 하고 있는게 맞네요. -
이동표(구름과비)
2014.07.09 09:26
free 함수가 영역 해제를 하는게 아니라 단순히 count 만 계산한다는 것에 주의해야할 듯 합니다.
그니깐, 64 k 공간을 malloc 을 이용해서 마음대로 할당해서 사용하되, malloc 호출 횟수만큼 반드시 free 를 호출해줘라...
그러면 그동안 사용한 공간을 한방에 모두 해제해주겠다. (해제란 것이 별게 아니고 pointer 만 초기 상태로)
뭐 이런 뜻이죠.
보통은 우리가 free 를 호출하려면 내부적으로 메모리 덩어리에 대한 포인터도 필요하고 size 도 필요하고 구현이 좀 복잡해지겠죠.
하지만, 압축 해제 과정에서 간단히 사용할 할당/해제 함수를 그렇게까지 구현할 필요도 없고 구현자체도 힘들 것입니다.
그래서, 그냥 맘대로 사용하고 마지막 free 에서 통째로 pointer 를 해제된 상태로 되돌리는 것입니다.
이게 제일 구현이 간단하겠네요.
-
보름달
2014.07.09 10:26
이동표님이 언급하셨듯이,
기본적으로 trivial 코드입니다.
count base로 구현한 것은, C++의 smart pointer 개념의 연장선으로 봤습니다.
해제하기 전에, 다시 할당하더라도, free_mem_end_ptr라는 임계값이 있으므로, 염려할 것은 없어 보입니다.
-
꾸물꾸무르g (이정록)
2014.07.09 11:31
trivial 코드를 왜 저렇게 구현했을까 궁금했는데, smart pointer 개념의 연장선 정도로 생각하니 어느 정도 납득이 가는 것 같습니다. 감사드립니다.
-
보름달
2014.07.09 13:36
참고로, 첨언하면,
C lib의 malloc은 시스템 콜이 아닙니다. 그냥 C lib이고, 구현하기 나름입니다.
참고: https://kldp.org/node/47166
"brk 시스템콜은 단지 프로세스의 데이터 세그먼트의 영역을 넓혀주는 일만 하는 것입니다. malloc 은 C-library에 있는 것이며, 데이터 세그먼트의 남는 영역을 잘 활용하여 heap용도로 사용하는 것일 뿐이고, 모자랄 경우 데이터 세그먼트를 늘여달라고 커널에 요청하는 것 뿐입니다.
즉, 커널 모드에서는 데이터 세그먼트의 증가를 요청 받을 뿐이지, 그 늘어난 양이 반드시 새로운 메모리 할당을 위해 사용되리라는 보장이 없습니다."
* malloc 구현예:
The C Programming Language" , 8.7 Example - A Storage Allocator
https://kldp.org/node/91877
* malloc 작동 원리:
http://minjang.egloos.com/1232908
감사합니다.
-
shepherd44
2014.07.09 17:34
첨부하신 주소에서도 재밌는게 많내요 감사히 보겠습니다 ㅎ
-
shepherd44
2014.07.09 17:02
상세한 답변 감사합니다 ㅎ 설마 실제 malloc이 저렇게 간단한가 라고 생각하면서 넘어갔었는데, 압축해제할때만 사용하는것이었군요.ㅎ;
.
안녕하세요.
arm11 A 팀의 이동표라고 합니다.
저희는 그 부분은 분석을 하지 않고 넘어갔는데 꼼꼼하게 분석하시네요. ^^
반성하게 됩니다. ㅎㅎ
질문을 하셔서 저도 소스를 좀 살펴보았는데요.
제 생각에는 이 부분을 심각하게 고민하지 않으셔도 될 것 같다는 생각이 듭니다.
왜냐하면, 여기에서 사용하는 malloc 은 주석에도 나와있다시피 "A trivial malloc implementation" 아주 사소하고
간단한 malloc 의 구현에 불과합니다.
압축 해제를 위해 잡아두었던 64k 공간을 사용하는 함수를 임시로 사용할 수 있도록 아주 간단하게 구현해 놓은 듯 합니다.
아직은 부팅부터 초기화단계니까 본격적으로 memory allocation 알고리즘을 사용할 단계는 아니니까요.
그래서, 소스를 보면 말씀하신대로 free 를 하나라도 누락했다면 malloc_ptr 는 커지기만 할 것입니다.
하지만, 방어가 아주 없는건 아니네요.
아래와 같이 malloc_ptr 이 free_mem_end_ptr 를 넘어가게 되면 malloc 실패가 됩니다.
free_mem_end_ptr 는 아마도 64 k 의 마지막 지점을 가리키고 있겠지요.
47 if (free_mem_end_ptr && malloc_ptr >= free_mem_end_ptr)
48 return NULL;
임시로 간단히 사용할 malloc 함수라면 이 정도의 구현으로도 충분하다고 봅니다.