Superkkt Blog

unsigned char *
dup_str(const unsigned char *format, ...)
{
    va_list ap;
    unsigned char msg[8192];

    ASSERT(format);

    va_start(ap, format);
    vsnprintf(msg, sizeof(msg), format, ap);
    va_end(ap);

    return (unsigned char *) strdup(msg);
}


문자열을 동적메모리로 복사해서 리턴하는 함수를 만들어서 사용했다. 원래 의도가 짧은 문자열을 동적메모리에 저장하려는 것이라서 내부 버퍼를 8192 바이트로 고정시키고 사용했는데, 이게 나중에 문제가 되었다. 프로그램 내부에서 이동하는 데이터가 계속 짤려서 넘어가는 것이였다. 한참 해메다가 발견한 이유가 내부 버퍼를 8192 바이트로 고정해서 계속 데이터가 그 사이즈 만큼만 복사가 된것이다. 왜 이런 상황을 생각하지 못했을까?

아무튼 위 함수에서는 가변인자를 받아서 처리하기 때문에 필요한 메모리의 총 사이즈를 구하기가 참 난감하다. 모든 가변인자를 strlen()으로 돌리는 방법이 있을 수 있지만 이것은 가변인자가 모두 char * 타입이라는 가정하에서만 가능하다.

해결 방법으로는 snprintf()의 리턴값을 이용하면 된다. snprintf()는 버퍼와 사이즈 인자를 각각 NULL과 0으로 해서 호출할경우 해당 인자들을 모두 저장하기 위해 필요한 버퍼의 사이즈를 리턴한다. 단, 이 값은 terminating null을 제외한 값이다. 따라서 +1을 해서 사용해야 한다. 단, 이 기능은 C99에서부터 표준으로 지정된 것이다. 따라서 C99 이전 컴파일러에서는 /dev/null에 fprintf로 write를 해서 나오는 값을 사용하도록 조건부 컴파일을 하도록 되어있다.

아래는 수정된 함수의 코드이다.

char *
dup_str(const char *format, ...)
{
   va_list ap;
   ssize_t len;
   char *ptr = NULL;

   va_start(ap, format);

   /* 필요한 메모리 사이즈 확인 */
#if __STDC_VERSION__ < 199901L
   FILE *nulldev = fopen("/dev/null", "w");
   if (!nulldev)
       return NULL;
   len = vfprintf(nulldev, format, ap);
   fclose(nulldev);
#else
   len = vsnprintf(NULL, 0, format, ap);
#endif
   if (len <= 0)
       return NULL;

   ptr = malloc(len + 1);
   if (!ptr)
       return NULL;

   va_start(ap, format);
   vsprintf(ptr, format, ap);
   va_end(ap);

   return ptr;
}
2007/01/05 09:22 2007/01/05 09:22

trackbacks

trackbacks rss

이 글에는 트랙백을 보낼 수 없습니다

Leave a Comment