Programming Languages

glibc/open_memstream() 소개

Sushi Yun 2015. 4. 12. 00:08

C에서 키보드로부터 입력을 받을 때 어떤 방식을 사용하시나요? 보통은 여유있는 고정된 크기의 배열을 버퍼로 많이 사용하죠?


char *input;
char buf[1024];
fgets(buf, sizeof(buf), stdin);
input = malloc(strlen(buf) + 1);
memset(input, 0, sizeof(input));
memcpy(input, buf, sizeof(input)); //input에 키보드 입력 저장


buf라는 1024bytes 크기의 배열에 키보드 입력을 받아온 후, 이를 바탕으로 input에 buf의 크기만큼 메모리공간을 할당, input에 buf를 복사합니다. 이렇게 되면 input에는 키보드 입력이 저장됩니다. 간단하죠.

그런데 역시 C는 귀찮아요, Java나 Scala였으면 짧게 해결되는데. =_=


Scanner s = new Scanner(System.in);
String input = s.nextLine();


아시다시피 다 C는 메모리를 개발자가 직접 관리를 할 수 있다는 어마무시한 장점인 동시에 일일이 관리를 해야한다는 단점 때문입니다. 아 귀찮아...

바로 그 때! 우연히 알게 된 좋은 함수가 있어서 소개해드리려고 합니다. 바로 glibc의 open_memstream()인데요. 메모리를 스트림처럼(FILE *를 통해 사용) 쓸 수 있게 해주는 함수입니다. 


#include <stdio.h>
FILE *open_memstream(char **ptr, size_t *sizeloc);


open_memstream()은 버퍼에 스트림을 열어서 이후 필요 시 버퍼 크기(ptr이 가리키는 메모리공간의 크기와 sizeloc의 값)가 알아서 커지도록 관리할 수 있도록 해줍니다. 스트림을 닫고 나서 메모리 공간을 수동으로 해제해줘야 한다는 번거로운 점이 있긴 한데, C에서 이것까지 자동으로 해주길 바라면 도둑놈심보(?)죠.

그밖의 주의사항으로는 glibc 2.7 이전 버전에서는 open_memstream()으로 생성한 스트림에 fseek()같은걸로 스트림의 끝을 가리키도변경하면 버퍼 크기가 자동으로 커지지 않았다고 합니다. 지금은 fseek()을 통한 스트림 위치 이동도 버퍼 크기에 자동으로 반영됩니다. open_memstream()에 대한 더 이상의 설명은 manpage 참고~


사실 이 글을 쓰게 된 이유는, 함수 자체에 대한 소개보다도 비교적 최근 있었던 이 함수의 버그 픽스 때문입니다. 먼저, 함수 원본 소스 코드는 여기 확인 참고해주세요.

버그에 대해 요약하면, open_memstream()의 호출이 실패한 경우 Memory Leak이 발생합니다. 왜냐하면, 함수 내에서 버퍼 메모리와 그 크기 변수에 대해 각각 메모리 할당을 하는데, 뒤의 할당이 실패한 경우 앞의 할당을 하지 않기 때문입니다. 2013년 9월 9일자에 반영된 패치(BZ #15892)는 이 내용이 수정되었습니다. 그리고 이 수정은 glibc v2.19에 포함되었습니다.

다시 말해, v2.18까지는 open_memstream()의 호출이 실패했을 때 메모리가 새는 현상이 있었다는 이야기지요. :( 앞으로의 사용에 참고하시길 바랍니다.

'Programming Languages' 카테고리의 다른 글

[추상자료형] 집합(Set)  (0) 2016.09.13
객체지향 Makefile 관리하기  (0) 2014.11.06
Expect cross-compile 문제 해결  (0) 2013.05.20